OSDN Git Service

* expr.c (expand_expr, case ADDR_EXPR): Only copy for misaligned if
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index c5276f2..afc43cc 100644 (file)
@@ -2,22 +2,22 @@
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
    2000, 2001 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -31,8 +31,11 @@ Boston, MA 02111-1307, USA.  */
 #include "except.h"
 #include "function.h"
 #include "insn-config.h"
+#include "insn-attr.h"
 /* Include expr.h after insn-config.h so we get HAVE_conditional_move.  */
 #include "expr.h"
+#include "optabs.h"
+#include "libfuncs.h"
 #include "recog.h"
 #include "reload.h"
 #include "output.h"
@@ -151,28 +154,26 @@ static int is_zeros_p             PARAMS ((tree));
 static int mostly_zeros_p      PARAMS ((tree));
 static void store_constructor_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
                                             HOST_WIDE_INT, enum machine_mode,
-                                            tree, tree, unsigned int, int,
-                                            int));
-static void store_constructor  PARAMS ((tree, rtx, unsigned int, int,
-                                        HOST_WIDE_INT));
+                                            tree, tree, int, int));
+static void store_constructor  PARAMS ((tree, rtx, int, HOST_WIDE_INT));
 static rtx store_field         PARAMS ((rtx, HOST_WIDE_INT,
                                         HOST_WIDE_INT, enum machine_mode,
-                                        tree, enum machine_mode, int,
-                                        unsigned int, HOST_WIDE_INT, int));
+                                        tree, enum machine_mode, int, tree,
+                                        int));
 static enum memory_use_mode
   get_memory_usage_from_modifier PARAMS ((enum expand_modifier));
-static tree save_noncopied_parts PARAMS ((tree, tree));
-static tree init_noncopied_parts PARAMS ((tree, tree));
-static int fixed_type_p                PARAMS ((tree));
 static rtx var_rtx             PARAMS ((tree));
-static rtx expand_expr_unaligned PARAMS ((tree, unsigned int *));
+static HOST_WIDE_INT highest_pow2_factor PARAMS ((tree));
 static rtx expand_increment    PARAMS ((tree, int, int));
 static void do_jump_by_parts_greater PARAMS ((tree, int, rtx, rtx));
 static void do_jump_by_parts_equality PARAMS ((tree, rtx, rtx));
 static void do_compare_and_jump        PARAMS ((tree, enum rtx_code, enum rtx_code,
                                         rtx, rtx));
 static rtx do_store_flag       PARAMS ((tree, rtx, enum machine_mode, int));
+#ifdef PUSH_ROUNDING
 static void emit_single_push_insn PARAMS ((enum machine_mode, rtx, tree));
+#endif
+static void do_tablejump PARAMS ((rtx, enum machine_mode, rtx, rtx, rtx));
 
 /* Record for each mode whether we can move a register directly to or
    from an object of that mode in memory.  If we can't, we won't try
@@ -363,10 +364,10 @@ enqueue_insn (var, body)
 
 rtx
 protect_from_queue (x, modify)
-     register rtx x;
+     rtx x;
      int modify;
 {
-  register RTX_CODE code = GET_CODE (x);
+  RTX_CODE code = GET_CODE (x);
 
 #if 0  /* A QUEUED can hang around after the queue is forced out.  */
   /* Shortcut for most common case.  */
@@ -384,23 +385,23 @@ protect_from_queue (x, modify)
       if (code == MEM && GET_MODE (x) != BLKmode
          && GET_CODE (XEXP (x, 0)) == QUEUED && !modify)
        {
-         register rtx y = XEXP (x, 0);
-         register rtx new = gen_rtx_MEM (GET_MODE (x), QUEUED_VAR (y));
-
-         MEM_COPY_ATTRIBUTES (new, x);
+         rtx y = XEXP (x, 0);
+         rtx new = replace_equiv_address_nv (x, QUEUED_VAR (y));
 
          if (QUEUED_INSN (y))
            {
-             register rtx temp = gen_reg_rtx (GET_MODE (new));
+             rtx temp = gen_reg_rtx (GET_MODE (x));
+
              emit_insn_before (gen_move_insn (temp, new),
                                QUEUED_INSN (y));
              return temp;
            }
+
          /* Copy the address into a pseudo, so that the returned value
             remains correct across calls to emit_queue.  */
-         XEXP (new, 0) = copy_to_reg (XEXP (new, 0));
-         return new;
+         return replace_equiv_address (new, copy_to_reg (XEXP (new, 0)));
        }
+
       /* Otherwise, recursively protect the subexpressions of all
         the kinds of rtx's that can contain a QUEUED.  */
       if (code == MEM)
@@ -451,7 +452,7 @@ int
 queued_subexp_p (x)
      rtx x;
 {
-  register enum rtx_code code = GET_CODE (x);
+  enum rtx_code code = GET_CODE (x);
   switch (code)
     {
     case QUEUED:
@@ -473,7 +474,7 @@ queued_subexp_p (x)
 void
 emit_queue ()
 {
-  register rtx p;
+  rtx p;
   while ((p = pending_chain))
     {
       rtx body = QUEUED_BODY (p);
@@ -496,7 +497,7 @@ emit_queue ()
 
 void
 convert_move (to, from, unsignedp)
-     register rtx to, from;
+     rtx to, from;
      int unsignedp;
 {
   enum machine_mode to_mode = GET_MODE (to);
@@ -541,9 +542,9 @@ convert_move (to, from, unsignedp)
        abort ();
 
       if (VECTOR_MODE_P (to_mode))
-       from = gen_rtx_SUBREG (to_mode, from, 0);
+       from = simplify_gen_subreg (to_mode, from, GET_MODE (from), 0);
       else
-       to = gen_rtx_SUBREG (from_mode, to, 0);
+       to = simplify_gen_subreg (from_mode, to, GET_MODE (to), 0);
 
       emit_move_insn (to, from);
       return;
@@ -875,7 +876,7 @@ convert_move (to, from, unsignedp)
              && STORE_FLAG_VALUE == -1)
            {
              emit_cmp_insn (lowfrom, const0_rtx, NE, NULL_RTX,
-                            lowpart_mode, 0, 0);
+                            lowpart_mode, 0);
              fill_value = gen_reg_rtx (word_mode);
              emit_insn (gen_slt (fill_value));
            }
@@ -1292,7 +1293,7 @@ convert_modes (mode, oldmode, x, unsignedp)
      rtx x;
      int unsignedp;
 {
-  register rtx temp;
+  rtx temp;
 
   /* If FROM is a SUBREG that indicates that we have already done at least
      the required extension, strip it.  */
@@ -1387,13 +1388,12 @@ convert_modes (mode, oldmode, x, unsignedp)
 #define MOVE_MAX_PIECES   MOVE_MAX
 #endif
 
-/* Generate several move instructions to copy LEN bytes
-   from block FROM to block TO.  (These are MEM rtx's with BLKmode).
-   The caller must pass FROM and TO
-    through protect_from_queue before calling.
+/* Generate several move instructions to copy LEN bytes from block FROM to
+   block TO.  (These are MEM rtx's with BLKmode).  The caller must pass FROM
+   and TO through protect_from_queue before calling.
 
-   When TO is NULL, the emit_single_push_insn is used to push the
-   FROM to stack.
+   If PUSH_ROUNDING is defined and TO is NULL, emit_single_push_insn is
+   used to push FROM to the stack.
 
    ALIGN is maximum alignment we can assume.  */
 
@@ -1566,7 +1566,7 @@ move_by_pieces_1 (genfun, mode, data)
      struct move_by_pieces *data;
 {
   unsigned int size = GET_MODE_SIZE (mode);
-  rtx to1, from1;
+  rtx to1 = NULL_RTX, from1;
 
   while (data->len >= size)
     {
@@ -1576,23 +1576,17 @@ move_by_pieces_1 (genfun, mode, data)
       if (data->to)
        {
          if (data->autinc_to)
-           {
-             to1 = gen_rtx_MEM (mode, data->to_addr);
-             MEM_COPY_ATTRIBUTES (to1, data->to);
-           }
+           to1 = adjust_automodify_address (data->to, mode, data->to_addr,
+                                            data->offset);
          else
-           to1 = change_address (data->to, mode,
-                                 plus_constant (data->to_addr, data->offset));
+           to1 = adjust_address (data->to, mode, data->offset);
        }
 
       if (data->autinc_from)
-       {
-         from1 = gen_rtx_MEM (mode, data->from_addr);
-         MEM_COPY_ATTRIBUTES (from1, data->from);
-       }
+       from1 = adjust_automodify_address (data->from, mode, data->from_addr,
+                                          data->offset);
       else
-       from1 = change_address (data->from, mode,
-                               plus_constant (data->from_addr, data->offset));
+       from1 = adjust_address (data->from, mode, data->offset);
 
       if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
        emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size)));
@@ -1602,7 +1596,13 @@ move_by_pieces_1 (genfun, mode, data)
       if (data->to)
        emit_insn ((*genfun) (to1, from1));
       else
-       emit_single_push_insn (mode, from1, NULL);
+       {
+#ifdef PUSH_ROUNDING
+         emit_single_push_insn (mode, from1, NULL);
+#else
+         abort ();
+#endif
+       }
 
       if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
        emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
@@ -1629,16 +1629,16 @@ move_by_pieces_1 (genfun, mode, data)
    0 otherwise.  */
 
 rtx
-emit_block_move (x, y, size, align)
+emit_block_move (x, y, size)
      rtx x, y;
      rtx size;
-     unsigned int align;
 {
   rtx retval = 0;
 #ifdef TARGET_MEM_FUNCTIONS
   static tree fn;
   tree call_expr, arg_list;
 #endif
+  unsigned int align = MIN (MEM_ALIGN (x), MEM_ALIGN (y));
 
   if (GET_MODE (x) != BLKmode)
     abort ();
@@ -1806,6 +1806,12 @@ emit_block_move (x, y, size, align)
                                          TREE_UNSIGNED (integer_type_node)),
                         TYPE_MODE (integer_type_node));
 #endif
+
+      /* If we are initializing a readonly value, show the above call
+        clobbered it.  Otherwise, a load from it may erroneously be hoisted
+        from a loop.  */
+      if (RTX_UNCHANGING_P (x))
+       emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
     }
 
   return retval;
@@ -1881,8 +1887,7 @@ move_block_from_reg (regno, x, nregs, size)
   if (size <= UNITS_PER_WORD
       && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode)
     {
-      emit_move_insn (change_address (x, mode, NULL),
-                     gen_rtx_REG (mode, regno));
+      emit_move_insn (adjust_address (x, mode, 0), gen_rtx_REG (mode, regno));
       return;
     }
 
@@ -1935,8 +1940,7 @@ move_block_from_reg (regno, x, nregs, size)
 
 /* Emit code to move a block SRC to a block DST, where DST is non-consecutive
    registers represented by a PARALLEL.  SSIZE represents the total size of
-   block SRC in bytes, or -1 if not known.  ALIGN is the known alignment of
-   SRC in bits.  */
+   block SRC in bytes, or -1 if not known.  */
 /* ??? If SSIZE % UNITS_PER_WORD != 0, we make the blatent assumption that
    the balance will be in what would be the low-order memory addresses, i.e.
    left justified for big endian, right justified for little endian.  This
@@ -1945,9 +1949,8 @@ move_block_from_reg (regno, x, nregs, size)
    would be needed.  */
 
 void
-emit_group_load (dst, orig_src, ssize, align)
+emit_group_load (dst, orig_src, ssize)
      rtx dst, orig_src;
-     unsigned int align;
      int ssize;
 {
   rtx *tmps, src;
@@ -1995,20 +1998,18 @@ emit_group_load (dst, orig_src, ssize, align)
            src = gen_reg_rtx (mode);
          else
            src = gen_reg_rtx (GET_MODE (orig_src));
+
          emit_move_insn (src, orig_src);
        }
 
       /* Optimize the access just a bit.  */
       if (GET_CODE (src) == MEM
-         && align >= GET_MODE_ALIGNMENT (mode)
+         && MEM_ALIGN (src) >= GET_MODE_ALIGNMENT (mode)
          && bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
          && bytelen == GET_MODE_SIZE (mode))
        {
          tmps[i] = gen_reg_rtx (mode);
-         emit_move_insn (tmps[i],
-                         change_address (src, mode,
-                                         plus_constant (XEXP (src, 0),
-                                                        bytepos)));
+         emit_move_insn (tmps[i], adjust_address (src, mode, bytepos));
        }
       else if (GET_CODE (src) == CONCAT)
        {
@@ -2018,6 +2019,13 @@ emit_group_load (dst, orig_src, ssize, align)
          else if (bytepos == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
                   && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 1))))
            tmps[i] = XEXP (src, 1);
+         else if (bytepos == 0)
+           {
+             rtx mem = assign_stack_temp (GET_MODE (src),
+                                          GET_MODE_SIZE (GET_MODE (src)), 0);
+             emit_move_insn (mem, src);
+             tmps[i] = adjust_address (mem, mode, 0);
+           }
          else
            abort ();
        }
@@ -2027,7 +2035,7 @@ emit_group_load (dst, orig_src, ssize, align)
       else
        tmps[i] = extract_bit_field (src, bytelen * BITS_PER_UNIT,
                                     bytepos * BITS_PER_UNIT, 1, NULL_RTX,
-                                    mode, mode, align, ssize);
+                                    mode, mode, ssize);
 
       if (BYTES_BIG_ENDIAN && shift)
        expand_binop (mode, ashl_optab, tmps[i], GEN_INT (shift),
@@ -2043,13 +2051,12 @@ emit_group_load (dst, orig_src, ssize, align)
 
 /* Emit code to move a block SRC to a block DST, where SRC is non-consecutive
    registers represented by a PARALLEL.  SSIZE represents the total size of
-   block DST, or -1 if not known.  ALIGN is the known alignment of DST.  */
+   block DST, or -1 if not known.  */
 
 void
-emit_group_store (orig_dst, src, ssize, align)
+emit_group_store (orig_dst, src, ssize)
      rtx orig_dst, src;
      int ssize;
-     unsigned int align;
 {
   rtx *tmps, dst;
   int start, i;
@@ -2093,8 +2100,8 @@ emit_group_store (orig_dst, src, ssize, align)
         the temporary.  */
 
       temp = assign_stack_temp (GET_MODE (dst), ssize, 0);
-      emit_group_store (temp, src, ssize, align);
-      emit_group_load (dst, temp, ssize, align);
+      emit_group_store (temp, src, ssize);
+      emit_group_load (dst, temp, ssize);
       return;
     }
   else if (GET_CODE (dst) != MEM)
@@ -2125,16 +2132,13 @@ emit_group_store (orig_dst, src, ssize, align)
 
       /* Optimize the access just a bit.  */
       if (GET_CODE (dst) == MEM
-         && align >= GET_MODE_ALIGNMENT (mode)
+         && MEM_ALIGN (dst) >= GET_MODE_ALIGNMENT (mode)
          && bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
          && bytelen == GET_MODE_SIZE (mode))
-       emit_move_insn (change_address (dst, mode,
-                                       plus_constant (XEXP (dst, 0),
-                                                      bytepos)),
-                       tmps[i]);
+       emit_move_insn (adjust_address (dst, mode, bytepos), tmps[i]);
       else
        store_bit_field (dst, bytelen * BITS_PER_UNIT, bytepos * BITS_PER_UNIT,
-                          mode, tmps[i], align, ssize);
+                        mode, tmps[i], ssize);
     }
 
   emit_queue ();
@@ -2215,8 +2219,8 @@ copy_blkmode_from_reg (tgtblk, srcreg, type)
                       extract_bit_field (src, bitsize,
                                          xbitpos % BITS_PER_WORD, 1,
                                          NULL_RTX, word_mode, word_mode,
-                                         bitsize, BITS_PER_WORD),
-                      bitsize, BITS_PER_WORD);
+                                         BITS_PER_WORD),
+                      BITS_PER_WORD);
     }
 
   return tgtblk;
@@ -2516,13 +2520,10 @@ store_by_pieces_2 (genfun, mode, data)
        data->offset -= size;
 
       if (data->autinc_to)
-       {
-         to1 = gen_rtx_MEM (mode, data->to_addr);
-         MEM_COPY_ATTRIBUTES (to1, data->to);
-       }
+       to1 = adjust_automodify_address (data->to, mode, data->to_addr,
+                                        data->offset);
       else
-       to1 = change_address (data->to, mode,
-                             plus_constant (data->to_addr, data->offset));
+       to1 = adjust_address (data->to, mode, data->offset);
 
       if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
        emit_insn (gen_add2_insn (data->to_addr,
@@ -2542,21 +2543,20 @@ store_by_pieces_2 (genfun, mode, data)
 }
 \f
 /* Write zeros through the storage of OBJECT.  If OBJECT has BLKmode, SIZE is
-   its length in bytes and ALIGN is the maximum alignment we can is has.
-
-   If we call a function that returns the length of the block, return it.  */
+   its length in bytes.  */
 
 rtx
-clear_storage (object, size, align)
+clear_storage (object, size)
      rtx object;
      rtx size;
-     unsigned int align;
 {
 #ifdef TARGET_MEM_FUNCTIONS
   static tree fn;
   tree call_expr, arg_list;
 #endif
   rtx retval = 0;
+  unsigned int align = (GET_CODE (object) == MEM ? MEM_ALIGN (object)
+                       : GET_MODE_ALIGNMENT (GET_MODE (object)));
 
   /* If OBJECT is not BLKmode and SIZE is the same size as its mode,
      just move a zero.  Otherwise, do this a piece at a time.  */
@@ -2686,7 +2686,7 @@ clear_storage (object, size, align)
          /* We need to make an argument list for the function call.
 
             memset has three arguments, the first is a void * addresses, the
-            second a integer with the initialization value, the last is a
+            second an integer with the initialization value, the last is a
             size_t byte count for the copy.  */
          arg_list
            = build_tree_list (NULL_TREE,
@@ -2712,6 +2712,12 @@ clear_storage (object, size, align)
                             VOIDmode, 2, object, Pmode, size,
                             TYPE_MODE (integer_type_node));
 #endif
+
+         /* If we are initializing a readonly value, show the above call
+            clobbered it.  Otherwise, a load from it may erroneously be
+            hoisted from a loop.  */
+         if (RTX_UNCHANGING_P (object))
+           emit_insn (gen_rtx_CLOBBER (VOIDmode, object));
        }
     }
 
@@ -2755,13 +2761,13 @@ emit_move_insn (x, y)
           && ! push_operand (x, GET_MODE (x)))
          || (flag_force_addr
              && CONSTANT_ADDRESS_P (XEXP (x, 0)))))
-    x = change_address (x, VOIDmode, XEXP (x, 0));
+    x = validize_mem (x);
 
   if (GET_CODE (y) == MEM
       && (! memory_address_p (GET_MODE (y), XEXP (y, 0))
          || (flag_force_addr
              && CONSTANT_ADDRESS_P (XEXP (y, 0)))))
-    y = change_address (y, VOIDmode, XEXP (y, 0));
+    y = validize_mem (y);
 
   if (mode == BLKmode)
     abort ();
@@ -2769,8 +2775,7 @@ emit_move_insn (x, y)
   last_insn = emit_move_insn_1 (x, y);
 
   if (y_cst && GET_CODE (x) == REG)
-    REG_NOTES (last_insn)
-      = gen_rtx_EXPR_LIST (REG_EQUAL, y_cst, REG_NOTES (last_insn));
+    set_unique_reg_note (last_insn, REG_EQUAL, y_cst);
 
   return last_insn;
 }
@@ -2911,7 +2916,7 @@ emit_move_insn_1 (x, y)
                    {
                      rtx mem = assign_stack_temp (reg_mode,
                                                   GET_MODE_SIZE (mode), 0);
-                     rtx cmem = change_address (mem, mode, NULL_RTX);
+                     rtx cmem = adjust_address (mem, mode, 0);
 
                      cfun->cannot_inline
                        = N_("function using short complex types cannot be inline");
@@ -2973,8 +2978,39 @@ emit_move_insn_1 (x, y)
         X with a reference to the stack pointer.  */
       if (push_operand (x, GET_MODE (x)))
        {
-         anti_adjust_stack (GEN_INT (GET_MODE_SIZE (GET_MODE (x))));
-         x = change_address (x, VOIDmode, stack_pointer_rtx);
+         rtx temp;
+         enum rtx_code code;
+         
+         /* Do not use anti_adjust_stack, since we don't want to update
+            stack_pointer_delta.  */
+         temp = expand_binop (Pmode,
+#ifdef STACK_GROWS_DOWNWARD
+                              sub_optab,
+#else
+                              add_optab,
+#endif
+                              stack_pointer_rtx,
+                              GEN_INT
+                                (PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)))),
+                              stack_pointer_rtx,
+                              0,
+                              OPTAB_LIB_WIDEN);
+          if (temp != stack_pointer_rtx)
+            emit_move_insn (stack_pointer_rtx, temp);
+
+         code = GET_CODE (XEXP (x, 0));
+         /* Just hope that small offsets off SP are OK.  */
+         if (code == POST_INC)
+           temp = gen_rtx_PLUS (Pmode, stack_pointer_rtx, 
+                               GEN_INT (-(HOST_WIDE_INT)
+                                          GET_MODE_SIZE (GET_MODE (x))));
+         else if (code == POST_DEC)
+           temp = gen_rtx_PLUS (Pmode, stack_pointer_rtx, 
+                               GEN_INT (GET_MODE_SIZE (GET_MODE (x))));
+         else
+           temp = stack_pointer_rtx;
+
+         x = change_address (x, VOIDmode, temp);
        }
 #endif
 
@@ -2982,20 +3018,10 @@ emit_move_insn_1 (x, y)
         is scheduled for replacement.  */
       if (reload_in_progress && GET_CODE (x) == MEM
          && (inner = find_replacement (&XEXP (x, 0))) != XEXP (x, 0))
-       {
-         rtx new = gen_rtx_MEM (GET_MODE (x), inner);
-
-         MEM_COPY_ATTRIBUTES (new, x);
-         x = new;
-       }
+       x = replace_equiv_address_nv (x, inner);
       if (reload_in_progress && GET_CODE (y) == MEM
          && (inner = find_replacement (&XEXP (y, 0))) != XEXP (y, 0))
-       {
-         rtx new = gen_rtx_MEM (GET_MODE (y), inner);
-
-         MEM_COPY_ATTRIBUTES (new, y);
-         y = new;
-       }
+       y = replace_equiv_address_nv (y, inner);
 
       start_sequence ();
 
@@ -3064,7 +3090,7 @@ push_block (size, extra, below)
      rtx size;
      int extra, below;
 {
-  register rtx temp;
+  rtx temp;
 
   size = convert_modes (Pmode, ptr_mode, size, 1);
   if (CONSTANT_P (size))
@@ -3081,18 +3107,11 @@ push_block (size, extra, below)
     }
 
 #ifndef STACK_GROWS_DOWNWARD
-#ifdef ARGS_GROW_DOWNWARD
-  if (!ACCUMULATE_OUTGOING_ARGS)
-#else
   if (0)
-#endif
 #else
   if (1)
 #endif
     {
-      /* Return the lowest stack address when STACK or ARGS grow downward and
-        we are not aaccumulating outgoing arguments (the c4x port uses such
-        conventions).  */
       temp = virtual_outgoing_args_rtx;
       if (extra != 0 && below)
        temp = plus_constant (temp, extra);
@@ -3114,14 +3133,14 @@ push_block (size, extra, below)
 }
 
 
-/* Return an rtx for the address of the beginning of a as-if-it-was-pushed
+/* Return an rtx for the address of the beginning of an as-if-it-was-pushed
    block of SIZE bytes.  */
 
 static rtx
 get_push_address (size)
      int size;
 {
-  register rtx temp;
+  rtx temp;
 
   if (STACK_PUSH_CODE == POST_DEC)
     temp = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (size));
@@ -3133,25 +3152,41 @@ get_push_address (size)
   return copy_to_reg (temp);
 }
 
+#ifdef PUSH_ROUNDING
+
 /* Emit single push insn.  */
+
 static void
 emit_single_push_insn (mode, x, type)
      rtx x;
      enum machine_mode mode;
      tree type;
 {
-#ifdef PUSH_ROUNDING
   rtx dest_addr;
-  int rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode));
+  unsigned rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode));
   rtx dest;
+  enum insn_code icode;
+  insn_operand_predicate_fn pred;
 
+  stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
+  /* If there is push pattern, use it.  Otherwise try old way of throwing
+     MEM representing push operation to move expander.  */
+  icode = push_optab->handlers[(int) mode].insn_code;
+  if (icode != CODE_FOR_nothing)
+    {
+      if (((pred = insn_data[(int) icode].operand[0].predicate)
+         && !((*pred) (x, mode))))
+       x = force_reg (mode, x);
+      emit_insn (GEN_FCN (icode) (x));
+      return;
+    }
   if (GET_MODE_SIZE (mode) == rounded_size)
     dest_addr = gen_rtx_fmt_e (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);
   else
     {
 #ifdef STACK_GROWS_DOWNWARD
       dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
-                               GEN_INT (-rounded_size));
+                               GEN_INT (-(HOST_WIDE_INT)rounded_size));
 #else
       dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
                                GEN_INT (rounded_size));
@@ -3161,8 +3196,6 @@ emit_single_push_insn (mode, x, type)
 
   dest = gen_rtx_MEM (mode, dest_addr);
 
-  stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
-
   if (type != 0)
     {
       set_mem_attributes (dest, type, 1);
@@ -3170,13 +3203,11 @@ emit_single_push_insn (mode, x, type)
          outgoing arguments and we cannot allow reordering of reads
          from function arguments with stores to outgoing arguments
          of sibling calls.  */
-      MEM_ALIAS_SET (dest) = 0;
+      set_mem_alias_set (dest, 0);
     }
   emit_move_insn (dest, x);
-#else
-  abort();
-#endif
 }
+#endif
 
 /* Generate code to push X onto the stack, assuming it has mode MODE and
    type TYPE.
@@ -3214,7 +3245,7 @@ void
 emit_push_insn (x, mode, type, size, align, partial, reg, extra,
                args_addr, args_so_far, reg_parm_stack_space,
                 alignment_pad)
-     register rtx x;
+     rtx x;
      enum machine_mode mode;
      tree type;
      rtx size;
@@ -3240,8 +3271,9 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
      Default is below for small data on big-endian machines; else above.  */
   enum direction where_pad = FUNCTION_ARG_PADDING (mode, type);
 
-  /* Invert direction if stack is post-update.  */
-  if (STACK_PUSH_CODE == POST_INC || STACK_PUSH_CODE == POST_DEC)
+  /* Invert direction if stack is post-decrement. 
+     FIXME: why?  */
+  if (STACK_PUSH_CODE == POST_DEC)
     if (where_pad != none)
       where_pad = (where_pad == downward ? upward : downward);
 
@@ -3251,7 +3283,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
     {
       /* Copy a block into the stack, entirely or partially.  */
 
-      register rtx temp;
+      rtx temp;
       int used = partial * UNITS_PER_WORD;
       int offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
       int skip;
@@ -3265,8 +3297,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
         because registers will take care of them.  */
 
       if (partial != 0)
-       xinner = change_address (xinner, BLKmode,
-                                plus_constant (XEXP (xinner, 0), used));
+       xinner = adjust_address (xinner, BLKmode, used);
 
       /* If the partial register-part of the arg counts in its stack size,
         skip the part of stack space corresponding to the registers.
@@ -3389,8 +3420,10 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
                 outgoing arguments and we cannot allow reordering of reads
                 from function arguments with stores to outgoing arguments
                 of sibling calls.  */
-             MEM_ALIAS_SET (target) = 0;
+             set_mem_alias_set (target, 0);
            }
+         else
+           set_mem_align (target, align);
 
          /* TEMP is the address of the block.  Copy the data there.  */
          if (GET_CODE (size) == CONST_INT
@@ -3572,7 +3605,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
                 outgoing arguments and we cannot allow reordering of reads
                 from function arguments with stores to outgoing arguments
                 of sibling calls.  */
-             MEM_ALIAS_SET (dest) = 0;
+             set_mem_alias_set (dest, 0);
            }
 
          emit_move_insn (dest, x);
@@ -3611,7 +3644,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
       /* Handle calls that pass values in multiple non-contiguous locations.
         The Irix 6 ABI has examples of this.  */
       if (GET_CODE (reg) == PARALLEL)
-       emit_group_load (reg, x, -1, align);  /* ??? size? */
+       emit_group_load (reg, x, -1);  /* ??? size? */
       else
        move_block_to_reg (REGNO (reg), x, partial, mode);
     }
@@ -3660,7 +3693,7 @@ expand_assignment (to, from, want_value, suggest_reg)
      int want_value;
      int suggest_reg ATTRIBUTE_UNUSED;
 {
-  register rtx to_rtx = 0;
+  rtx to_rtx = 0;
   rtx result;
 
   /* Don't crash if the lhs of the assignment was erroneous.  */
@@ -3682,15 +3715,15 @@ expand_assignment (to, from, want_value, suggest_reg)
     {
       enum machine_mode mode1;
       HOST_WIDE_INT bitsize, bitpos;
+      rtx orig_to_rtx;
       tree offset;
       int unsignedp;
       int volatilep = 0;
       tree tem;
-      unsigned int alignment;
 
       push_temp_slots ();
       tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
-                                &unsignedp, &volatilep, &alignment);
+                                &unsignedp, &volatilep);
 
       /* If we are going to use store_bit_field and extract_bit_field,
         make sure to_rtx will be safe for multiple use.  */
@@ -3698,7 +3731,8 @@ expand_assignment (to, from, want_value, suggest_reg)
       if (mode1 == VOIDmode && want_value)
        tem = stabilize_reference (tem);
 
-      to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_DONT);
+      orig_to_rtx = to_rtx
+       = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_DONT);
       if (offset != 0)
        {
          rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
@@ -3707,72 +3741,64 @@ expand_assignment (to, from, want_value, suggest_reg)
            abort ();
 
          if (GET_MODE (offset_rtx) != ptr_mode)
-           {
+           offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
+
 #ifdef POINTERS_EXTEND_UNSIGNED
-             offset_rtx = convert_memory_address (ptr_mode, offset_rtx);
-#else
-             offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
+         if (GET_MODE (offset_rtx) != Pmode)
+           offset_rtx = convert_memory_address (Pmode, offset_rtx);
 #endif
-           }
 
          /* A constant address in TO_RTX can have VOIDmode, we must not try
             to call force_reg for that case.  Avoid that case.  */
          if (GET_CODE (to_rtx) == MEM
              && GET_MODE (to_rtx) == BLKmode
              && GET_MODE (XEXP (to_rtx, 0)) != VOIDmode
-             && bitsize
+             && bitsize > 0
              && (bitpos % bitsize) == 0
              && (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
-             && alignment == GET_MODE_ALIGNMENT (mode1))
+             && MEM_ALIGN (to_rtx) == GET_MODE_ALIGNMENT (mode1))
            {
-             rtx temp = change_address (to_rtx, mode1,
-                                        plus_constant (XEXP (to_rtx, 0),
-                                                       (bitpos /
-                                                        BITS_PER_UNIT)));
+             rtx temp
+               = adjust_address (to_rtx, mode1, bitpos / BITS_PER_UNIT);
+
              if (GET_CODE (XEXP (temp, 0)) == REG)
                to_rtx = temp;
              else
-               to_rtx = change_address (to_rtx, mode1,
-                                        force_reg (GET_MODE (XEXP (temp, 0)),
-                                                   XEXP (temp, 0)));
+               to_rtx = (replace_equiv_address
+                         (to_rtx, force_reg (GET_MODE (XEXP (temp, 0)),
+                                             XEXP (temp, 0))));
              bitpos = 0;
            }
 
-         to_rtx = change_address (to_rtx, VOIDmode,
-                                  gen_rtx_PLUS (ptr_mode, XEXP (to_rtx, 0),
-                                                force_reg (ptr_mode,
-                                                           offset_rtx)));
+         to_rtx = offset_address (to_rtx, offset_rtx,
+                                  highest_pow2_factor (offset));
        }
 
-      if (volatilep)
-       {
-         if (GET_CODE (to_rtx) == MEM)
-           {
-             /* When the offset is zero, to_rtx is the address of the
-                structure we are storing into, and hence may be shared.
-                We must make a new MEM before setting the volatile bit.  */
-             if (offset == 0)
-               to_rtx = copy_rtx (to_rtx);
 
-             MEM_VOLATILE_P (to_rtx) = 1;
-           }
-#if 0  /* This was turned off because, when a field is volatile
-         in an object which is not volatile, the object may be in a register,
-         and then we would abort over here.  */
-         else
-           abort ();
-#endif
+      /* Deal with volatile and readonly fields.  The former is only done
+        for MEM.  Also set MEM_KEEP_ALIAS_SET_P if needed.  */
+      if (volatilep && GET_CODE (to_rtx) == MEM)
+       {
+         if (to_rtx == orig_to_rtx)
+           to_rtx = copy_rtx (to_rtx);
+         MEM_VOLATILE_P (to_rtx) = 1;
        }
 
       if (TREE_CODE (to) == COMPONENT_REF
          && TREE_READONLY (TREE_OPERAND (to, 1)))
        {
-         if (offset == 0)
+         if (to_rtx == orig_to_rtx)
            to_rtx = copy_rtx (to_rtx);
-
          RTX_UNCHANGING_P (to_rtx) = 1;
        }
 
+      if (! can_address_p (to))
+       {
+         if (to_rtx == orig_to_rtx)
+           to_rtx = copy_rtx (to_rtx);
+         MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
+       }
+
       /* Check the access.  */
       if (current_function_check_memory_usage && GET_CODE (to_rtx) == MEM)
        {
@@ -3788,7 +3814,7 @@ expand_assignment (to, from, want_value, suggest_reg)
            best_mode = QImode;
 
          best_mode_size = GET_MODE_BITSIZE (best_mode);
-         to_addr = plus_constant (XEXP (to_rtx, 0), (bitpos / BITS_PER_UNIT));
+         to_addr = plus_constant (XEXP (to_rtx, 0), bitpos / BITS_PER_UNIT);
          size = CEIL ((bitpos % best_mode_size) + bitsize, best_mode_size);
          size *= GET_MODE_SIZE (best_mode);
 
@@ -3803,48 +3829,25 @@ expand_assignment (to, from, want_value, suggest_reg)
          in_check_memory_usage = 0;
        }
 
-      /* If this is a varying-length object, we must get the address of
-        the source and do an explicit block move.  */
-      if (bitsize < 0)
-       {
-         unsigned int from_align;
-         rtx from_rtx = expand_expr_unaligned (from, &from_align);
-         rtx inner_to_rtx
-           = change_address (to_rtx, BLKmode,
-                             plus_constant (XEXP (to_rtx, 0),
-                                            bitpos / BITS_PER_UNIT));
-
-         emit_block_move (inner_to_rtx, from_rtx, expr_size (from),
-                          MIN (alignment, from_align));
-         free_temp_slots ();
-         pop_temp_slots ();
-         return to_rtx;
-       }
-      else
-       {
-         result = store_field (to_rtx, bitsize, bitpos, mode1, from,
-                               (want_value
-                                /* Spurious cast for HPUX compiler.  */
-                                ? ((enum machine_mode)
-                                   TYPE_MODE (TREE_TYPE (to)))
-                                : VOIDmode),
-                               unsignedp,
-                               alignment,
-                               int_size_in_bytes (TREE_TYPE (tem)),
-                               get_alias_set (to));
+      result = store_field (to_rtx, bitsize, bitpos, mode1, from,
+                           (want_value
+                            /* Spurious cast for HPUX compiler.  */
+                            ? ((enum machine_mode)
+                               TYPE_MODE (TREE_TYPE (to)))
+                            : VOIDmode),
+                           unsignedp, TREE_TYPE (tem), get_alias_set (to));
 
-         preserve_temp_slots (result);
-         free_temp_slots ();
-         pop_temp_slots ();
+      preserve_temp_slots (result);
+      free_temp_slots ();
+      pop_temp_slots ();
 
-         /* If the value is meaningful, convert RESULT to the proper mode.
-            Otherwise, return nothing.  */
-         return (want_value ? convert_modes (TYPE_MODE (TREE_TYPE (to)),
-                                             TYPE_MODE (TREE_TYPE (from)),
-                                             result,
-                                             TREE_UNSIGNED (TREE_TYPE (to)))
-                 : NULL_RTX);
-       }
+      /* If the value is meaningful, convert RESULT to the proper mode.
+        Otherwise, return nothing.  */
+      return (want_value ? convert_modes (TYPE_MODE (TREE_TYPE (to)),
+                                         TYPE_MODE (TREE_TYPE (from)),
+                                         result,
+                                         TREE_UNSIGNED (TREE_TYPE (to)))
+             : NULL_RTX);
     }
 
   /* If the rhs is a function call and its value is not an aggregate,
@@ -3872,16 +3875,14 @@ expand_assignment (to, from, want_value, suggest_reg)
       /* Handle calls that return values in multiple non-contiguous locations.
         The Irix 6 ABI has examples of this.  */
       if (GET_CODE (to_rtx) == PARALLEL)
-       emit_group_load (to_rtx, value, int_size_in_bytes (TREE_TYPE (from)),
-                        TYPE_ALIGN (TREE_TYPE (from)));
+       emit_group_load (to_rtx, value, int_size_in_bytes (TREE_TYPE (from)));
       else if (GET_MODE (to_rtx) == BLKmode)
-       emit_block_move (to_rtx, value, expr_size (from),
-                        TYPE_ALIGN (TREE_TYPE (from)));
+       emit_block_move (to_rtx, value, expr_size (from));
       else
        {
 #ifdef POINTERS_EXTEND_UNSIGNED
-         if (TREE_CODE (TREE_TYPE (to)) == REFERENCE_TYPE
-            || TREE_CODE (TREE_TYPE (to)) == POINTER_TYPE)
+         if (POINTER_TYPE_P (TREE_TYPE (to))
+             && GET_MODE (to_rtx) != GET_MODE (value))
            value = convert_memory_address (GET_MODE (to_rtx), value);
 #endif
          emit_move_insn (to_rtx, value);
@@ -3896,11 +3897,7 @@ expand_assignment (to, from, want_value, suggest_reg)
      Don't re-expand if it was expanded already (in COMPONENT_REF case).  */
 
   if (to_rtx == 0)
-    {
-      to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_WO);
-      if (GET_CODE (to_rtx) == MEM)
-       MEM_ALIAS_SET (to_rtx) = get_alias_set (to);
-    }
+    to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_WO);
 
   /* Don't move directly into a return register.  */
   if (TREE_CODE (to) == RESULT_DECL
@@ -3912,8 +3909,7 @@ expand_assignment (to, from, want_value, suggest_reg)
       temp = expand_expr (from, 0, GET_MODE (to_rtx), 0);
 
       if (GET_CODE (to_rtx) == PARALLEL)
-       emit_group_load (to_rtx, temp, int_size_in_bytes (TREE_TYPE (from)),
-                        TYPE_ALIGN (TREE_TYPE (from)));
+       emit_group_load (to_rtx, temp, int_size_in_bytes (TREE_TYPE (from)));
       else
        emit_move_insn (to_rtx, temp);
 
@@ -4003,11 +3999,11 @@ expand_assignment (to, from, want_value, suggest_reg)
 
 rtx
 store_expr (exp, target, want_value)
-     register tree exp;
-     register rtx target;
+     tree exp;
+     rtx target;
      int want_value;
 {
-  register rtx temp;
+  rtx temp;
   int dont_return_target = 0;
   int dont_store_target = 0;
 
@@ -4132,9 +4128,13 @@ store_expr (exp, target, want_value)
       /* If TEMP is a VOIDmode constant, use convert_modes to make
         sure that we properly convert it.  */
       if (CONSTANT_P (temp) && GET_MODE (temp) == VOIDmode)
-       temp = convert_modes (GET_MODE (SUBREG_REG (target)),
-                             TYPE_MODE (TREE_TYPE (exp)), temp,
-                             SUBREG_PROMOTED_UNSIGNED_P (target));
+       {
+         temp = convert_modes (GET_MODE (target), TYPE_MODE (TREE_TYPE (exp)),
+                               temp, SUBREG_PROMOTED_UNSIGNED_P (target));
+         temp = convert_modes (GET_MODE (SUBREG_REG (target)),
+                               GET_MODE (target), temp,
+                               SUBREG_PROMOTED_UNSIGNED_P (target));
+       }
 
       convert_move (SUBREG_REG (target), temp,
                    SUBREG_PROMOTED_UNSIGNED_P (target));
@@ -4251,7 +4251,7 @@ store_expr (exp, target, want_value)
          size = expr_size (exp);
          if (GET_CODE (size) == CONST_INT
              && INTVAL (size) < TREE_STRING_LENGTH (exp))
-           emit_block_move (target, temp, size, TYPE_ALIGN (TREE_TYPE (exp)));
+           emit_block_move (target, temp, size);
          else
            {
              /* Compute the size of the data to copy from the string.  */
@@ -4259,14 +4259,12 @@ store_expr (exp, target, want_value)
                = size_binop (MIN_EXPR,
                              make_tree (sizetype, size),
                              size_int (TREE_STRING_LENGTH (exp)));
-             unsigned int align = TYPE_ALIGN (TREE_TYPE (exp));
              rtx copy_size_rtx = expand_expr (copy_size, NULL_RTX,
                                               VOIDmode, 0);
              rtx label = 0;
 
              /* Copy that much.  */
-             emit_block_move (target, temp, copy_size_rtx,
-                              TYPE_ALIGN (TREE_TYPE (exp)));
+             emit_block_move (target, temp, copy_size_rtx);
 
              /* Figure out how much is left in TARGET that we have to clear.
                 Do all calculations in ptr_mode.  */
@@ -4278,10 +4276,6 @@ store_expr (exp, target, want_value)
                {
                  addr = plus_constant (addr, TREE_STRING_LENGTH (exp));
                  size = plus_constant (size, -TREE_STRING_LENGTH (exp));
-                 align = MIN (align,
-                              (unsigned int) (BITS_PER_UNIT
-                                              * (INTVAL (copy_size_rtx)
-                                                 & - INTVAL (copy_size_rtx))));
                }
              else
                {
@@ -4294,12 +4288,10 @@ store_expr (exp, target, want_value)
                                       copy_size_rtx, NULL_RTX, 0,
                                       OPTAB_LIB_WIDEN);
 
-                 align = BITS_PER_UNIT;
                  label = gen_label_rtx ();
                  emit_cmp_and_jump_insns (size, const0_rtx, LT, NULL_RTX,
-                                          GET_MODE (size), 0, 0, label);
+                                          GET_MODE (size), 0, label);
                }
-             align = MIN (align, expr_align (copy_size));
 
              if (size != const0_rtx)
                {
@@ -4317,7 +4309,7 @@ store_expr (exp, target, want_value)
                                       GEN_INT (MEMORY_USE_WO),
                                       TYPE_MODE (integer_type_node));
                  in_check_memory_usage = 0;
-                 clear_storage (dest, size, align);
+                 clear_storage (dest, size);
                }
 
              if (label)
@@ -4327,11 +4319,9 @@ store_expr (exp, target, want_value)
       /* Handle calls that return values in multiple non-contiguous locations.
         The Irix 6 ABI has examples of this.  */
       else if (GET_CODE (target) == PARALLEL)
-       emit_group_load (target, temp, int_size_in_bytes (TREE_TYPE (exp)),
-                        TYPE_ALIGN (TREE_TYPE (exp)));
+       emit_group_load (target, temp, int_size_in_bytes (TREE_TYPE (exp)));
       else if (GET_MODE (temp) == BLKmode)
-       emit_block_move (target, temp, expr_size (exp),
-                        TYPE_ALIGN (TREE_TYPE (exp)));
+       emit_block_move (target, temp, expr_size (exp));
       else
        emit_move_insn (target, temp);
     }
@@ -4430,7 +4420,7 @@ mostly_zeros_p (exp)
 /* Helper function for store_constructor.
    TARGET, BITSIZE, BITPOS, MODE, EXP are as for store_field.
    TYPE is the type of the CONSTRUCTOR, not the element type.
-   ALIGN and CLEARED are as for store_constructor.
+   CLEARED is as for store_constructor.
    ALIAS_SET is the alias set to use for any stores.
 
    This provides a recursive shortcut back to store_constructor when it isn't
@@ -4439,14 +4429,13 @@ mostly_zeros_p (exp)
    clear a substructure if the outer structure has already been cleared.  */
 
 static void
-store_constructor_field (target, bitsize, bitpos,
-                        mode, exp, type, align, cleared, alias_set)
+store_constructor_field (target, bitsize, bitpos, mode, exp, type, cleared,
+                        alias_set)
      rtx target;
      unsigned HOST_WIDE_INT bitsize;
      HOST_WIDE_INT bitpos;
      enum machine_mode mode;
      tree exp, type;
-     unsigned int align;
      int cleared;
      int alias_set;
 {
@@ -4457,44 +4446,42 @@ store_constructor_field (target, bitsize, bitpos,
         generate unnecessary clear instructions anyways.  */
       && (bitpos == 0 || GET_CODE (target) == MEM))
     {
-      if (bitpos != 0)
+      if (GET_CODE (target) == MEM)
        target
-         = change_address (target,
+         = adjust_address (target,
                            GET_MODE (target) == BLKmode
                            || 0 != (bitpos
                                     % GET_MODE_ALIGNMENT (GET_MODE (target)))
-                           ? BLKmode : VOIDmode,
-                           plus_constant (XEXP (target, 0),
-                                          bitpos / BITS_PER_UNIT));
+                           ? BLKmode : VOIDmode, bitpos / BITS_PER_UNIT);
 
 
-      /* Show the alignment may no longer be what it was and update the alias
-        set, if required.  */
-      if (bitpos != 0)
-       align = MIN (align, (unsigned int) bitpos & - bitpos);
-      if (GET_CODE (target) == MEM)
-       MEM_ALIAS_SET (target) = alias_set;
+      /* Update the alias set, if required.  */
+      if (GET_CODE (target) == MEM && ! MEM_KEEP_ALIAS_SET_P (target)
+         && MEM_ALIAS_SET (target) != 0)
+       {
+         target = copy_rtx (target);
+         set_mem_alias_set (target, alias_set);
+       }
 
-      store_constructor (exp, target, align, cleared, bitsize / BITS_PER_UNIT);
+      store_constructor (exp, target, cleared, bitsize / BITS_PER_UNIT);
     }
   else
-    store_field (target, bitsize, bitpos, mode, exp, VOIDmode, 0, align,
-                int_size_in_bytes (type), alias_set);
+    store_field (target, bitsize, bitpos, mode, exp, VOIDmode, 0, type,
+                alias_set);
 }
 
 /* Store the value of constructor EXP into the rtx TARGET.
-   TARGET is either a REG or a MEM.
-   ALIGN is the maximum known alignment for TARGET.
+   TARGET is either a REG or a MEM; we know it cannot conflict, since
+   safe_from_p has been called.
    CLEARED is true if TARGET is known to have been zero'd.
    SIZE is the number of bytes of TARGET we are allowed to modify: this
    may not be the same as the size of EXP if we are assigning to a field
    which has been packed to exclude padding bits.  */
 
 static void
-store_constructor (exp, target, align, cleared, size)
+store_constructor (exp, target, cleared, size)
      tree exp;
      rtx target;
-     unsigned int align;
      int cleared;
      HOST_WIDE_INT size;
 {
@@ -4503,47 +4490,30 @@ store_constructor (exp, target, align, cleared, size)
   HOST_WIDE_INT exp_size = int_size_in_bytes (type);
 #endif
 
-  /* We know our target cannot conflict, since safe_from_p has been called.  */
-#if 0
-  /* Don't try copying piece by piece into a hard register
-     since that is vulnerable to being clobbered by EXP.
-     Instead, construct in a pseudo register and then copy it all.  */
-  if (GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER)
-    {
-      rtx temp = gen_reg_rtx (GET_MODE (target));
-      store_constructor (exp, temp, align, cleared, size);
-      emit_move_insn (target, temp);
-      return;
-    }
-#endif
-
   if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
       || TREE_CODE (type) == QUAL_UNION_TYPE)
     {
-      register tree elt;
+      tree elt;
 
-      /* Inform later passes that the whole union value is dead.  */
+      /* We either clear the aggregate or indicate the value is dead.  */
       if ((TREE_CODE (type) == UNION_TYPE
           || TREE_CODE (type) == QUAL_UNION_TYPE)
-         && ! cleared)
+         && ! cleared
+         && ! CONSTRUCTOR_ELTS (exp))
+       /* If the constructor is empty, clear the union.  */
        {
-         emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
-
-         /* If the constructor is empty, clear the union.  */
-         if (! CONSTRUCTOR_ELTS (exp)  && ! cleared)
-           clear_storage (target, expr_size (exp), TYPE_ALIGN (type));
+         clear_storage (target, expr_size (exp));
+         cleared = 1;
        }
 
       /* If we are building a static constructor into a register,
         set the initial value as zero so we can fold the value into
         a constant.  But if more than one register is involved,
         this probably loses.  */
-      else if (GET_CODE (target) == REG && TREE_STATIC (exp)
+      else if (! cleared && GET_CODE (target) == REG && TREE_STATIC (exp)
               && GET_MODE_SIZE (GET_MODE (target)) <= UNITS_PER_WORD)
        {
-         if (! cleared)
-           emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
-
+         emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
          cleared = 1;
        }
 
@@ -4552,20 +4522,19 @@ store_constructor (exp, target, align, cleared, size)
         clear the whole structure first.  Don't do this if TARGET is a
         register whose mode size isn't equal to SIZE since clear_storage
         can't handle this case.  */
-      else if (size > 0
+      else if (! cleared && size > 0
               && ((list_length (CONSTRUCTOR_ELTS (exp))
                    != fields_length (type))
                   || mostly_zeros_p (exp))
               && (GET_CODE (target) != REG
-                  || (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (target)) == size))
+                  || ((HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (target))
+                      == size)))
        {
-         if (! cleared)
-           clear_storage (target, GEN_INT (size), align);
-
+         clear_storage (target, GEN_INT (size));
          cleared = 1;
        }
-      else if (! cleared)
-       /* Inform later passes that the old value is dead.  */
+
+      if (! cleared)
        emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
 
       /* Store each element of the constructor into
@@ -4573,11 +4542,11 @@ store_constructor (exp, target, align, cleared, size)
 
       for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
        {
-         register tree field = TREE_PURPOSE (elt);
+         tree field = TREE_PURPOSE (elt);
 #ifdef WORD_REGISTER_OPERATIONS
          tree value = TREE_VALUE (elt);
 #endif
-         register enum machine_mode mode;
+         enum machine_mode mode;
          HOST_WIDE_INT bitsize;
          HOST_WIDE_INT bitpos = 0;
          int unsignedp;
@@ -4626,20 +4595,15 @@ store_constructor (exp, target, align, cleared, size)
                abort ();
 
              if (GET_MODE (offset_rtx) != ptr_mode)
-               {
+               offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
+
 #ifdef POINTERS_EXTEND_UNSIGNED
-                  offset_rtx = convert_memory_address (ptr_mode, offset_rtx);
-#else
-                  offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
+             if (GET_MODE (offset_rtx) != Pmode)
+               offset_rtx = convert_memory_address (Pmode, offset_rtx);
 #endif
-                }
-
-             to_rtx
-               = change_address (to_rtx, VOIDmode,
-                                 gen_rtx_PLUS (ptr_mode, XEXP (to_rtx, 0),
-                                               force_reg (ptr_mode,
-                                                          offset_rtx)));
-             align = DECL_OFFSET_ALIGN (field);
+
+             to_rtx = offset_address (to_rtx, offset_rtx,
+                                      highest_pow2_factor (offset));
            }
 
          if (TREE_READONLY (field))
@@ -4664,11 +4628,13 @@ store_constructor (exp, target, align, cleared, size)
              && bitpos + BITS_PER_WORD <= exp_size * BITS_PER_UNIT)
            {
              tree type = TREE_TYPE (value);
+
              if (TYPE_PRECISION (type) < BITS_PER_WORD)
                {
                  type = type_for_size (BITS_PER_WORD, TREE_UNSIGNED (type));
                  value = convert (type, value);
                }
+
              if (BYTES_BIG_ENDIAN)
                value
                  = fold (build (LSHIFT_EXPR, type, value,
@@ -4677,25 +4643,32 @@ store_constructor (exp, target, align, cleared, size)
              mode = word_mode;
            }
 #endif
+
+         if (GET_CODE (to_rtx) == MEM && !MEM_KEEP_ALIAS_SET_P (to_rtx)
+             && DECL_NONADDRESSABLE_P (field))
+           {
+             to_rtx = copy_rtx (to_rtx);
+             MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
+           }
+
          store_constructor_field (to_rtx, bitsize, bitpos, mode,
-                                  TREE_VALUE (elt), type, align, cleared,
-                                  (DECL_NONADDRESSABLE_P (field)
-                                   && GET_CODE (to_rtx) == MEM)
-                                  ? MEM_ALIAS_SET (to_rtx)
-                                  : get_alias_set (TREE_TYPE (field)));
+                                  TREE_VALUE (elt), type, cleared,
+                                  get_alias_set (TREE_TYPE (field)));
        }
     }
   else if (TREE_CODE (type) == ARRAY_TYPE)
     {
-      register tree elt;
-      register int i;
+      tree elt;
+      int i;
       int need_to_clear;
       tree domain = TYPE_DOMAIN (type);
       tree elttype = TREE_TYPE (type);
-      int const_bounds_p = (host_integerp (TYPE_MIN_VALUE (domain), 0)
+      int const_bounds_p = (TYPE_MIN_VALUE (domain)
+                           && TYPE_MAX_VALUE (domain)
+                           && host_integerp (TYPE_MIN_VALUE (domain), 0)
                            && host_integerp (TYPE_MAX_VALUE (domain), 0));
-      HOST_WIDE_INT minelt;
-      HOST_WIDE_INT maxelt;
+      HOST_WIDE_INT minelt = 0;
+      HOST_WIDE_INT maxelt = 0;
 
       /* If we have constant bounds for the range of the type, get them.  */
       if (const_bounds_p)
@@ -4757,10 +4730,10 @@ store_constructor (exp, target, align, cleared, size)
       if (need_to_clear && size > 0)
        {
          if (! cleared)
-           clear_storage (target, GEN_INT (size), align);
+           clear_storage (target, GEN_INT (size));
          cleared = 1;
        }
-      else
+      else if (REG_P (target))
        /* Inform later passes that the old value is dead.  */
        emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
 
@@ -4771,12 +4744,11 @@ store_constructor (exp, target, align, cleared, size)
           elt;
           elt = TREE_CHAIN (elt), i++)
        {
-         register enum machine_mode mode;
+         enum machine_mode mode;
          HOST_WIDE_INT bitsize;
          HOST_WIDE_INT bitpos;
          int unsignedp;
          tree value = TREE_VALUE (elt);
-         unsigned int align = TYPE_ALIGN (TREE_TYPE (value));
          tree index = TREE_PURPOSE (elt);
          rtx xtarget = target;
 
@@ -4796,7 +4768,7 @@ store_constructor (exp, target, align, cleared, size)
            {
              tree lo_index = TREE_OPERAND (index, 0);
              tree hi_index = TREE_OPERAND (index, 1);
-             rtx index_r, pos_rtx, addr, hi_r, loop_top, loop_end;
+             rtx index_r, pos_rtx, hi_r, loop_top, loop_end;
              struct nesting *loop;
              HOST_WIDE_INT lo, hi, count;
              tree position;
@@ -4818,11 +4790,18 @@ store_constructor (exp, target, align, cleared, size)
                  for (; lo <= hi; lo++)
                    {
                      bitpos = lo * tree_low_cst (TYPE_SIZE (elttype), 0);
+
+                     if (GET_CODE (target) == MEM
+                         && !MEM_KEEP_ALIAS_SET_P (target)
+                         && TYPE_NONALIASED_COMPONENT (type))
+                       {
+                         target = copy_rtx (target);
+                         MEM_KEEP_ALIAS_SET_P (target) = 1;
+                       }
+
                      store_constructor_field
-                       (target, bitsize, bitpos, mode, value, type, align,
-                        cleared,
-                        TYPE_NONALIASED_COMPONENT (type)
-                        ? MEM_ALIAS_SET (target) : get_alias_set (elttype));
+                       (target, bitsize, bitpos, mode, value, type, cleared,
+                        get_alias_set (elttype));
                    }
                }
              else
@@ -4860,10 +4839,11 @@ store_constructor (exp, target, align, cleared, size)
                                                  TYPE_SIZE_UNIT (elttype)));
 
                  pos_rtx = expand_expr (position, 0, VOIDmode, 0);
-                 addr = gen_rtx_PLUS (Pmode, XEXP (target, 0), pos_rtx);
-                 xtarget = change_address (target, mode, addr);
+                 xtarget = offset_address (target, pos_rtx,
+                                           highest_pow2_factor (position));
+                 xtarget = adjust_address (xtarget, mode, 0);
                  if (TREE_CODE (value) == CONSTRUCTOR)
-                   store_constructor (value, xtarget, align, cleared,
+                   store_constructor (value, xtarget, cleared,
                                       bitsize / BITS_PER_UNIT);
                  else
                    store_expr (value, xtarget, 0);
@@ -4882,7 +4862,6 @@ store_constructor (exp, target, align, cleared, size)
          else if ((index != 0 && ! host_integerp (index, 0))
                   || ! host_integerp (TYPE_SIZE (elttype), 1))
            {
-             rtx pos_rtx, addr;
              tree position;
 
              if (index == 0)
@@ -4896,9 +4875,10 @@ store_constructor (exp, target, align, cleared, size)
              position = size_binop (MULT_EXPR, index,
                                     convert (ssizetype,
                                              TYPE_SIZE_UNIT (elttype)));
-             pos_rtx = expand_expr (position, 0, VOIDmode, 0);
-             addr = gen_rtx_PLUS (Pmode, XEXP (target, 0), pos_rtx);
-             xtarget = change_address (target, mode, addr);
+             xtarget = offset_address (target,
+                                       expand_expr (position, 0, VOIDmode, 0),
+                                       highest_pow2_factor (position));
+             xtarget = adjust_address (xtarget, mode, 0);
              store_expr (value, xtarget, 0);
            }
          else
@@ -4909,12 +4889,15 @@ store_constructor (exp, target, align, cleared, size)
              else
                bitpos = (i * tree_low_cst (TYPE_SIZE (elttype), 1));
 
+             if (GET_CODE (target) == MEM && !MEM_KEEP_ALIAS_SET_P (target)
+                 && TYPE_NONALIASED_COMPONENT (type))
+               {
+                 target = copy_rtx (target);
+                 MEM_KEEP_ALIAS_SET_P (target) = 1;
+               }
+
              store_constructor_field (target, bitsize, bitpos, mode, value,
-                                      type, align, cleared,
-                                      TYPE_NONALIASED_COMPONENT (type)
-                                      && GET_CODE (target) == MEM
-                                      ? MEM_ALIAS_SET (target) :
-                                      get_alias_set (elttype));
+                                      type, cleared, get_alias_set (elttype));
 
            }
        }
@@ -4942,7 +4925,7 @@ store_constructor (exp, target, align, cleared, size)
       if (elt == NULL_TREE && size > 0)
        {
          if (!cleared)
-           clear_storage (target, GEN_INT (size), TYPE_ALIGN (type));
+           clear_storage (target, GEN_INT (size));
          return;
        }
 
@@ -4991,10 +4974,7 @@ store_constructor (exp, target, align, cleared, size)
                         XEXP if the set is multi-word, but not if
                         it's single-word.  */
                      if (GET_CODE (target) == MEM)
-                       {
-                         to_rtx = plus_constant (XEXP (target, 0), offset);
-                         to_rtx = change_address (target, mode, to_rtx);
-                       }
+                       to_rtx = adjust_address (target, mode, offset);
                      else if (offset == 0)
                        to_rtx = target;
                      else
@@ -5020,7 +5000,7 @@ store_constructor (exp, target, align, cleared, size)
                   || (tree_low_cst (TREE_VALUE (elt), 0)
                       - tree_low_cst (TREE_PURPOSE (elt), 0) + 1
                       != (HOST_WIDE_INT) nbits))))
-         clear_storage (target, expr_size (exp), TYPE_ALIGN (type));
+         clear_storage (target, expr_size (exp));
 
       for (; elt != NULL_TREE; elt = TREE_CHAIN (elt))
        {
@@ -5117,16 +5097,15 @@ store_constructor (exp, target, align, cleared, size)
    has mode VALUE_MODE if that is convenient to do.
    In this case, UNSIGNEDP must be nonzero if the value is an unsigned type.
 
-   ALIGN is the alignment that TARGET is known to have.
-   TOTAL_SIZE is the size in bytes of the structure, or -1 if varying.
+   TYPE is the type of the underlying object,
 
    ALIAS_SET is the alias set for the destination.  This value will
    (in general) be different from that for TARGET, since TARGET is a
    reference to the containing structure.  */
 
 static rtx
-store_field (target, bitsize, bitpos, mode, exp, value_mode,
-            unsignedp, align, total_size, alias_set)
+store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
+            alias_set)
      rtx target;
      HOST_WIDE_INT bitsize;
      HOST_WIDE_INT bitpos;
@@ -5134,8 +5113,7 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
      tree exp;
      enum machine_mode value_mode;
      int unsignedp;
-     unsigned int align;
-     HOST_WIDE_INT total_size;
+     tree type;
      int alias_set;
 {
   HOST_WIDE_INT width_mask = 0;
@@ -5147,8 +5125,7 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
      side-effects.  */
   if (bitsize == 0)
     return expand_expr (exp, const0_rtx, VOIDmode, 0);
-
-  if (bitsize < HOST_BITS_PER_WIDE_INT)
+  else if (bitsize >=0 && bitsize < HOST_BITS_PER_WIDE_INT)
     width_mask = ((HOST_WIDE_INT) 1 << bitsize) - 1;
 
   /* If we are storing into an unaligned field of an aligned union that is
@@ -5167,23 +5144,22 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
     {
       rtx object
        = assign_temp
-         (build_qualified_type (type_for_mode (GET_MODE (target), 0),
-                                TYPE_QUAL_CONST),
+         (build_qualified_type (type, TYPE_QUALS (type) | TYPE_QUAL_CONST),
           0, 1, 1);
       rtx blk_object = copy_rtx (object);
 
       PUT_MODE (blk_object, BLKmode);
+      MEM_COPY_ATTRIBUTES (blk_object, object);
 
       if (bitsize != (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (target)))
        emit_move_insn (object, target);
 
-      store_field (blk_object, bitsize, bitpos, mode, exp, VOIDmode, 0,
-                  align, total_size, alias_set);
+      store_field (blk_object, bitsize, bitpos, mode, exp, VOIDmode, 0, type,
+                  alias_set);
 
-      /* Even though we aren't returning target, we need to
-        give it the updated value.  */
       emit_move_insn (target, object);
 
+      /* We want to return the BLKmode version of the data.  */
       return blk_object;
     }
 
@@ -5208,12 +5184,9 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
       || GET_CODE (target) == SUBREG
       /* If the field isn't aligned enough to store as an ordinary memref,
         store it as a bit field.  */
-      || (mode != BLKmode && SLOW_UNALIGNED_ACCESS (mode, align)
-         && (align < GET_MODE_ALIGNMENT (mode)
+      || (mode != BLKmode && SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (target))
+         && (MEM_ALIGN (target) < GET_MODE_ALIGNMENT (mode)
              || bitpos % GET_MODE_ALIGNMENT (mode)))
-      || (mode == BLKmode && SLOW_UNALIGNED_ACCESS (mode, align)
-         && (TYPE_ALIGN (TREE_TYPE (exp)) > align
-             || bitpos % TYPE_ALIGN (TREE_TYPE (exp)) != 0))
       /* If the RHS and field are a constant size and the size of the
         RHS isn't the same size as the bitfield, we must use bitfield
         operations.  */
@@ -5246,38 +5219,26 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
         boundary.  If so, we simply do a block copy.  */
       if (GET_MODE (target) == BLKmode && GET_MODE (temp) == BLKmode)
        {
-         unsigned int exp_align = expr_align (exp);
-
          if (GET_CODE (target) != MEM || GET_CODE (temp) != MEM
              || bitpos % BITS_PER_UNIT != 0)
            abort ();
 
-         target = change_address (target, VOIDmode,
-                                  plus_constant (XEXP (target, 0),
-                                               bitpos / BITS_PER_UNIT));
-
-         /* Make sure that ALIGN is no stricter than the alignment of EXP.  */
-         align = MIN (exp_align, align);
-
-         /* Find an alignment that is consistent with the bit position.  */
-         while ((bitpos % align) != 0)
-           align >>= 1;
-
+         target = adjust_address (target, VOIDmode, bitpos / BITS_PER_UNIT);
          emit_block_move (target, temp,
-                          bitsize == -1 ? expr_size (exp)
-                          : GEN_INT ((bitsize + BITS_PER_UNIT - 1)
-                                     / BITS_PER_UNIT),
-                          align);
+                          GEN_INT ((bitsize + BITS_PER_UNIT - 1)
+                                   / BITS_PER_UNIT));
 
          return value_mode == VOIDmode ? const0_rtx : target;
        }
 
       /* Store the value in the bitfield.  */
-      store_bit_field (target, bitsize, bitpos, mode, temp, align, total_size);
+      store_bit_field (target, bitsize, bitpos, mode, temp,
+                      int_size_in_bytes (type));
+
       if (value_mode != VOIDmode)
        {
-         /* The caller wants an rtx for the value.  */
-         /* If possible, avoid refetching from the bitfield itself.  */
+         /* The caller wants an rtx for the value.
+            If possible, avoid refetching from the bitfield itself.  */
          if (width_mask != 0
              && ! (GET_CODE (target) == MEM && MEM_VOLATILE_P (target)))
            {
@@ -5292,6 +5253,7 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
                                     GET_MODE (temp) == VOIDmode
                                     ? value_mode
                                     : GET_MODE (temp))), NULL_RTX);
+
              tmode = GET_MODE (temp);
              if (tmode == VOIDmode)
                tmode = value_mode;
@@ -5299,16 +5261,17 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
              temp = expand_shift (LSHIFT_EXPR, tmode, temp, count, 0, 0);
              return expand_shift (RSHIFT_EXPR, tmode, temp, count, 0, 0);
            }
+
          return extract_bit_field (target, bitsize, bitpos, unsignedp,
-                                   NULL_RTX, value_mode, 0, align,
-                                   total_size);
+                                   NULL_RTX, value_mode, VOIDmode,
+                                   int_size_in_bytes (type));
        }
       return const0_rtx;
     }
   else
     {
       rtx addr = XEXP (target, 0);
-      rtx to_rtx;
+      rtx to_rtx = target;
 
       /* If a value is wanted, it must be the lhs;
         so make the address stable for multiple use.  */
@@ -5320,25 +5283,18 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
                && GET_CODE (XEXP (addr, 1)) == CONST_INT
                && (XEXP (addr, 0) == virtual_incoming_args_rtx
                    || XEXP (addr, 0) == virtual_stack_vars_rtx)))
-       addr = copy_to_reg (addr);
+       to_rtx = replace_equiv_address (to_rtx, copy_to_reg (addr));
 
       /* Now build a reference to just the desired component.  */
 
-      to_rtx = copy_rtx (change_address (target, mode,
-                                        plus_constant (addr,
-                                                       (bitpos
-                                                        / BITS_PER_UNIT))));
+      to_rtx = adjust_address (target, mode, bitpos / BITS_PER_UNIT);
+
+      if (to_rtx == target)
+       to_rtx = copy_rtx (to_rtx);
+
       MEM_SET_IN_STRUCT_P (to_rtx, 1);
-      /* If the address of the structure varies, then it might be on
-        the stack.  And, stack slots may be shared across scopes.
-        So, two different structures, of different types, can end up
-        at the same location.  We will give the structures alias set
-        zero; here we must be careful not to give non-zero alias sets
-        to their fields.  */
-      if (!rtx_varies_p (addr, /*for_alias=*/0))
-       MEM_ALIAS_SET (to_rtx) = alias_set;
-      else
-       MEM_ALIAS_SET (to_rtx) = 0;
+      if (!MEM_KEEP_ALIAS_SET_P (to_rtx) && MEM_ALIAS_SET (to_rtx) != 0)
+       set_mem_alias_set (to_rtx, alias_set);
 
       return store_expr (exp, to_rtx, value_mode != VOIDmode);
     }
@@ -5354,9 +5310,6 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
    giving the variable offset (in units) in *POFFSET.
    This offset is in addition to the bit position.
    If the position is not variable, we store 0 in *POFFSET.
-   We set *PALIGNMENT to the alignment of the address that will be
-   computed.  This is the alignment of the thing we return if *POFFSET
-   is zero, but can be more less strictly aligned if *POFFSET is nonzero.
 
    If any of the extraction expressions is volatile,
    we store 1 in *PVOLATILEP.  Otherwise we don't change that.
@@ -5367,11 +5320,11 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
 
    If the field describes a variable-sized object, *PMODE is set to
    VOIDmode and *PBITSIZE is set to -1.  An access cannot be made in
-   this case, but the address of the object can be found.   */
+   this case, but the address of the object can be found.  */
 
 tree
 get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
-                    punsignedp, pvolatilep, palignment)
+                    punsignedp, pvolatilep)
      tree exp;
      HOST_WIDE_INT *pbitsize;
      HOST_WIDE_INT *pbitpos;
@@ -5379,13 +5332,12 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
      enum machine_mode *pmode;
      int *punsignedp;
      int *pvolatilep;
-     unsigned int *palignment;
 {
   tree size_tree = 0;
   enum machine_mode mode = VOIDmode;
   tree offset = size_zero_node;
   tree bit_offset = bitsize_zero_node;
-  unsigned int alignment = BIGGEST_ALIGNMENT;
+  tree placeholder_ptr = 0;
   tree tem;
 
   /* First get the mode, signedness, and size.  We do this from just the
@@ -5446,8 +5398,7 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
          bit_offset = size_binop (PLUS_EXPR, bit_offset,
                                   DECL_FIELD_BIT_OFFSET (field));
 
-         if (! host_integerp (offset, 0))
-           alignment = MIN (alignment, DECL_OFFSET_ALIGN (field));
+         /* ??? Right now we don't do anything with DECL_OFFSET_ALIGN.  */
        }
 
       else if (TREE_CODE (exp) == ARRAY_REF
@@ -5483,6 +5434,20 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
                                           unit_size));
        }
 
+      else if (TREE_CODE (exp) == PLACEHOLDER_EXPR)
+       {
+         tree new = find_placeholder (exp, &placeholder_ptr);
+
+         /* If we couldn't find the replacement, return the PLACEHOLDER_EXPR.
+            We might have been called from tree optimization where we
+            haven't set up an object yet.  */
+         if (new == 0)
+           break;
+         else
+           exp = new;
+
+         continue;
+       }
       else if (TREE_CODE (exp) != NON_LVALUE_EXPR
               && ! ((TREE_CODE (exp) == NOP_EXPR
                      || TREE_CODE (exp) == CONVERT_EXPR)
@@ -5494,19 +5459,9 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
       if (TREE_THIS_VOLATILE (exp))
        *pvolatilep = 1;
 
-      /* If the offset is non-constant already, then we can't assume any
-        alignment more than the alignment here.  */
-      if (! TREE_CONSTANT (offset))
-       alignment = MIN (alignment, TYPE_ALIGN (TREE_TYPE (exp)));
-
       exp = TREE_OPERAND (exp, 0);
     }
 
-  if (DECL_P (exp))
-    alignment = MIN (alignment, DECL_ALIGN (exp));
-  else if (TREE_TYPE (exp) != 0)
-    alignment = MIN (alignment, TYPE_ALIGN (TREE_TYPE (exp)));
-
   /* If OFFSET is constant, see if we can return the whole thing as a
      constant bit position.  Otherwise, split it up.  */
   if (host_integerp (offset, 0)
@@ -5519,7 +5474,6 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
     *pbitpos = tree_low_cst (bit_offset, 0), *poffset = offset;
 
   *pmode = mode;
-  *palignment = alignment;
   return exp;
 }
 
@@ -5565,13 +5519,13 @@ rtx
 force_operand (value, target)
      rtx value, target;
 {
-  register optab binoptab = 0;
+  optab binoptab = 0;
   /* Use a temporary to force order of execution of calls to
      `force_operand'.  */
   rtx tmp;
-  register rtx op2;
+  rtx op2;
   /* Use subtarget as the target for operand 0 of a binary operation.  */
-  register rtx subtarget = get_subtarget (target);
+  rtx subtarget = get_subtarget (target);
 
   /* Check for a PIC address load.  */
   if (flag_pic
@@ -5642,72 +5596,25 @@ force_operand (value, target)
       /* We give UNSIGNEDP = 0 to expand_binop
         because the only operations we are expanding here are signed ones.  */
     }
-  return value;
-}
-\f
-/* Subroutine of expand_expr:
-   save the non-copied parts (LIST) of an expr (LHS), and return a list
-   which can restore these values to their previous values,
-   should something modify their storage.  */
-
-static tree
-save_noncopied_parts (lhs, list)
-     tree lhs;
-     tree list;
-{
-  tree tail;
-  tree parts = 0;
-
-  for (tail = list; tail; tail = TREE_CHAIN (tail))
-    if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
-      parts = chainon (parts, save_noncopied_parts (lhs, TREE_VALUE (tail)));
-    else
-      {
-       tree part = TREE_VALUE (tail);
-       tree part_type = TREE_TYPE (part);
-       tree to_be_saved = build (COMPONENT_REF, part_type, lhs, part);
-       rtx target
-         = assign_temp (build_qualified_type (part_type,
-                                              (TYPE_QUALS (part_type)
-                                               | TYPE_QUAL_CONST)),
-                        0, 1, 1);
-
-       if (! memory_address_p (TYPE_MODE (part_type), XEXP (target, 0)))
-         target = change_address (target, TYPE_MODE (part_type), NULL_RTX);
-       parts = tree_cons (to_be_saved,
-                          build (RTL_EXPR, part_type, NULL_TREE,
-                                 (tree) target),
-                          parts);
-       store_expr (TREE_PURPOSE (parts), RTL_EXPR_RTL (TREE_VALUE (parts)), 0);
-      }
-  return parts;
-}
 
-/* Subroutine of expand_expr:
-   record the non-copied parts (LIST) of an expr (LHS), and return a list
-   which specifies the initial values of these parts.  */
-
-static tree
-init_noncopied_parts (lhs, list)
-     tree lhs;
-     tree list;
-{
-  tree tail;
-  tree parts = 0;
+#ifdef INSN_SCHEDULING
+  /* On machines that have insn scheduling, we want all memory reference to be
+     explicit, so we need to deal with such paradoxical SUBREGs.  */
+  if (GET_CODE (value) == SUBREG && GET_CODE (SUBREG_REG (value)) == MEM
+      && (GET_MODE_SIZE (GET_MODE (value))
+         > GET_MODE_SIZE (GET_MODE (SUBREG_REG (value)))))
+    value
+      = simplify_gen_subreg (GET_MODE (value),
+                            force_reg (GET_MODE (SUBREG_REG (value)),
+                                       force_operand (SUBREG_REG (value),
+                                                      NULL_RTX)),
+                            GET_MODE (SUBREG_REG (value)),
+                            SUBREG_BYTE (value));
+#endif
 
-  for (tail = list; tail; tail = TREE_CHAIN (tail))
-    if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
-      parts = chainon (parts, init_noncopied_parts (lhs, TREE_VALUE (tail)));
-    else if (TREE_PURPOSE (tail))
-      {
-       tree part = TREE_VALUE (tail);
-       tree part_type = TREE_TYPE (part);
-       tree to_be_initialized = build (COMPONENT_REF, part_type, lhs, part);
-       parts = tree_cons (TREE_PURPOSE (tail), to_be_initialized, parts);
-      }
-  return parts;
+  return value;
 }
-
+\f
 /* Subroutine of expand_expr: return nonzero iff there is no way that
    EXP can reference X, which is being modified.  TOP_P is nonzero if this
    call is going to be used to determine whether we need a temporary
@@ -5819,9 +5726,26 @@ safe_from_p (x, exp, top_p)
       switch (TREE_CODE (exp))
        {
        case ADDR_EXPR:
-         return (staticp (TREE_OPERAND (exp, 0))
-                 || TREE_STATIC (exp)
-                 || safe_from_p (x, TREE_OPERAND (exp, 0), 0));
+         /* If the operand is static or we are static, we can't conflict.
+            Likewise if we don't conflict with the operand at all.  */
+         if (staticp (TREE_OPERAND (exp, 0))
+             || TREE_STATIC (exp)
+             || safe_from_p (x, TREE_OPERAND (exp, 0), 0))
+           return 1;
+
+         /* Otherwise, the only way this can conflict is if we are taking
+            the address of a DECL a that address if part of X, which is
+            very rare.  */
+         exp = TREE_OPERAND (exp, 0);
+         if (DECL_P (exp))
+           {
+             if (!DECL_RTL_SET_P (exp)
+                 || GET_CODE (DECL_RTL (exp)) != MEM)
+               return 0;
+             else
+               exp_rtl = XEXP (DECL_RTL (exp), 0);
+           }
+         break;
 
        case INDIRECT_REF:
          if (GET_CODE (x) == MEM
@@ -5849,7 +5773,7 @@ safe_from_p (x, exp, top_p)
          break;
 
        case WITH_CLEANUP_EXPR:
-         exp_rtl = RTL_EXPR_RTL (exp);
+         exp_rtl = WITH_CLEANUP_EXPR_RTL (exp);
          break;
 
        case CLEANUP_POINT_EXPR:
@@ -5882,7 +5806,7 @@ safe_from_p (x, exp, top_p)
          return safe_from_p (x, TREE_OPERAND (exp, 1), 0);
 
        case METHOD_CALL_EXPR:
-         /* This takes a rtx argument, but shouldn't appear here.  */
+         /* This takes an rtx argument, but shouldn't appear here.  */
          abort ();
 
        default:
@@ -5932,22 +5856,6 @@ safe_from_p (x, exp, top_p)
   return 1;
 }
 
-/* Subroutine of expand_expr: return nonzero iff EXP is an
-   expression whose type is statically determinable.  */
-
-static int
-fixed_type_p (exp)
-     tree exp;
-{
-  if (TREE_CODE (exp) == PARM_DECL
-      || TREE_CODE (exp) == VAR_DECL
-      || TREE_CODE (exp) == CALL_EXPR || TREE_CODE (exp) == TARGET_EXPR
-      || TREE_CODE (exp) == COMPONENT_REF
-      || TREE_CODE (exp) == ARRAY_REF)
-    return 1;
-  return 0;
-}
-
 /* Subroutine of expand_expr: return rtx if EXP is a
    variable or parameter; else return 0.  */
 
@@ -6021,6 +5929,128 @@ check_max_integer_computation_mode (exp)
 }
 #endif
 \f
+/* Return the highest power of two that EXP is known to be a multiple of.
+   This is used in updating alignment of MEMs in array references.  */
+
+static HOST_WIDE_INT
+highest_pow2_factor (exp)
+     tree exp;
+{
+  HOST_WIDE_INT c0, c1;
+
+  switch (TREE_CODE (exp))
+    {
+    case INTEGER_CST:
+      /* If the integer is expressable in a HOST_WIDE_INT, we can find the
+        lowest bit that's a one.  If the result is zero, pessimize by
+        returning 1.  This is overly-conservative, but such things should not
+        happen in the offset expressions that we are called with.  */
+      if (host_integerp (exp, 0))
+       {
+         c0 = tree_low_cst (exp, 0);
+         c0 = c0 < 0 ? - c0 : c0;
+         return c0 != 0 ? c0 & -c0 : 1;
+       }
+      break;
+
+    case PLUS_EXPR:  case MINUS_EXPR:
+      c0 = highest_pow2_factor (TREE_OPERAND (exp, 0));
+      c1 = highest_pow2_factor (TREE_OPERAND (exp, 1));
+      return MIN (c0, c1);
+
+    case MULT_EXPR:
+      c0 = highest_pow2_factor (TREE_OPERAND (exp, 0));
+      c1 = highest_pow2_factor (TREE_OPERAND (exp, 1));
+      return c0 * c1;
+
+    case ROUND_DIV_EXPR:  case TRUNC_DIV_EXPR:  case FLOOR_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+      c0 = highest_pow2_factor (TREE_OPERAND (exp, 0));
+      c1 = highest_pow2_factor (TREE_OPERAND (exp, 1));
+      return MAX (1, c0 / c1);
+
+    case NON_LVALUE_EXPR:  case NOP_EXPR:  case CONVERT_EXPR:
+    case COMPOUND_EXPR:    case SAVE_EXPR: case WITH_RECORD_EXPR:
+      return highest_pow2_factor (TREE_OPERAND (exp, 0));
+
+    case COND_EXPR:
+      c0 = highest_pow2_factor (TREE_OPERAND (exp, 1));
+      c1 = highest_pow2_factor (TREE_OPERAND (exp, 2));
+      return MIN (c0, c1);
+
+    default:
+      break;
+    }
+
+  return 1;
+}
+\f
+/* Return an object on the placeholder list that matches EXP, a
+   PLACEHOLDER_EXPR.  An object "matches" if it is of the type of the
+   PLACEHOLDER_EXPR or a pointer type to it.  For further information, see
+   tree.def.  If no such object is found, return 0.  If PLIST is nonzero, it
+   is a location which initially points to a starting location in the
+   placeholder list (zero means start of the list) and where a pointer into
+   the placeholder list at which the object is found is placed.  */
+
+tree
+find_placeholder (exp, plist)
+     tree exp;
+     tree *plist;
+{
+  tree type = TREE_TYPE (exp);
+  tree placeholder_expr;
+
+  for (placeholder_expr
+       = plist && *plist ? TREE_CHAIN (*plist) : placeholder_list;
+       placeholder_expr != 0;
+       placeholder_expr = TREE_CHAIN (placeholder_expr))
+    {
+      tree need_type = TYPE_MAIN_VARIANT (type);
+      tree elt;
+
+      /* Find the outermost reference that is of the type we want.  If none,
+        see if any object has a type that is a pointer to the type we
+        want.  */
+      for (elt = TREE_PURPOSE (placeholder_expr); elt != 0;
+          elt = ((TREE_CODE (elt) == COMPOUND_EXPR
+                  || TREE_CODE (elt) == COND_EXPR)
+                 ? TREE_OPERAND (elt, 1)
+                 : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+                    || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+                    || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+                    || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
+                 ? TREE_OPERAND (elt, 0) : 0))
+       if (TYPE_MAIN_VARIANT (TREE_TYPE (elt)) == need_type)
+         {
+           if (plist)
+             *plist = placeholder_expr;
+           return elt;
+         }
+
+      for (elt = TREE_PURPOSE (placeholder_expr); elt != 0;
+          elt
+          = ((TREE_CODE (elt) == COMPOUND_EXPR
+              || TREE_CODE (elt) == COND_EXPR)
+             ? TREE_OPERAND (elt, 1)
+             : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+                || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+                || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+                || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
+             ? TREE_OPERAND (elt, 0) : 0))
+       if (POINTER_TYPE_P (TREE_TYPE (elt))
+           && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (elt)))
+               == need_type))
+         {
+           if (plist)
+             *plist = placeholder_expr;
+           return build1 (INDIRECT_REF, need_type, elt);
+         }
+    }
+
+  return 0;
+}
+\f
 /* expand_expr: generate code for computing expression EXP.
    An rtx for the computed value is returned.  The value is never null.
    In the case of a void EXP, const0_rtx is returned.
@@ -6058,16 +6088,16 @@ check_max_integer_computation_mode (exp)
 
 rtx
 expand_expr (exp, target, tmode, modifier)
-     register tree exp;
+     tree exp;
      rtx target;
      enum machine_mode tmode;
      enum expand_modifier modifier;
 {
-  register rtx op0, op1, temp;
+  rtx op0, op1, temp;
   tree type = TREE_TYPE (exp);
   int unsignedp = TREE_UNSIGNED (type);
-  register enum machine_mode mode;
-  register enum tree_code code = TREE_CODE (exp);
+  enum machine_mode mode;
+  enum tree_code code = TREE_CODE (exp);
   optab this_optab;
   rtx subtarget, original_target;
   int ignore;
@@ -6331,12 +6361,13 @@ expand_expr (exp, target, tmode, modifier)
            abort ();
          addr = XEXP (DECL_RTL (exp), 0);
          if (GET_CODE (addr) == MEM)
-           addr = change_address (addr, Pmode,
-                                  fix_lexical_addr (XEXP (addr, 0), exp));
+           addr
+             = replace_equiv_address (addr,
+                                      fix_lexical_addr (XEXP (addr, 0), exp));
          else
            addr = fix_lexical_addr (addr, exp);
 
-         temp = change_address (DECL_RTL (exp), mode, addr);
+         temp = replace_equiv_address (DECL_RTL (exp), addr);
        }
 
       /* This is the case of an array whose size is to be determined
@@ -6345,8 +6376,7 @@ expand_expr (exp, target, tmode, modifier)
 
       else if (GET_CODE (DECL_RTL (exp)) == MEM
               && GET_CODE (XEXP (DECL_RTL (exp), 0)) == REG)
-       temp = change_address (DECL_RTL (exp), GET_MODE (DECL_RTL (exp)),
-                              XEXP (DECL_RTL (exp), 0));
+       temp = validize_mem (DECL_RTL (exp));
 
       /* If DECL_RTL is memory, we are in the normal case and either
         the address is not valid or it is not a register and -fforce-addr
@@ -6360,8 +6390,8 @@ expand_expr (exp, target, tmode, modifier)
                                       XEXP (DECL_RTL (exp), 0))
                   || (flag_force_addr
                       && GET_CODE (XEXP (DECL_RTL (exp), 0)) != REG)))
-       temp = change_address (DECL_RTL (exp), VOIDmode,
-                              copy_rtx (XEXP (DECL_RTL (exp), 0)));
+       temp = replace_equiv_address (DECL_RTL (exp),
+                                     copy_rtx (XEXP (DECL_RTL (exp), 0)));
 
       /* If we got something, return it.  But first, set the alignment
         if the address is a register.  */
@@ -6430,8 +6460,8 @@ expand_expr (exp, target, tmode, modifier)
          && (! memory_address_p (mode, XEXP (TREE_CST_RTL (exp), 0))
              || (flag_force_addr
                  && GET_CODE (XEXP (TREE_CST_RTL (exp), 0)) != REG)))
-       return change_address (TREE_CST_RTL (exp), VOIDmode,
-                              copy_rtx (XEXP (TREE_CST_RTL (exp), 0)));
+       return replace_equiv_address (TREE_CST_RTL (exp),
+                                     copy_rtx (XEXP (TREE_CST_RTL (exp), 0)));
       return TREE_CST_RTL (exp);
 
     case EXPR_WITH_FILE_LOCATION:
@@ -6443,7 +6473,7 @@ expand_expr (exp, target, tmode, modifier)
        lineno = EXPR_WFL_LINENO (exp);
        if (EXPR_WFL_EMIT_LINE_NOTE (exp))
          emit_line_note (input_filename, lineno);
-       /* Possibly avoid switching back and force here.  */
+       /* Possibly avoid switching back and forth here.  */
        to_return = expand_expr (EXPR_WFL_NODE (exp), target, tmode, modifier);
        input_filename = saved_input_filename;
        lineno = saved_lineno;
@@ -6480,8 +6510,9 @@ expand_expr (exp, target, tmode, modifier)
            }
          if (temp == 0 || GET_CODE (temp) != MEM)
            abort ();
-         return change_address (temp, mode,
-                                fix_lexical_addr (XEXP (temp, 0), exp));
+         return
+           replace_equiv_address (temp,
+                                  fix_lexical_addr (XEXP (temp, 0), exp));
        }
       if (SAVE_EXPR_RTL (exp) == 0)
        {
@@ -6547,66 +6578,17 @@ expand_expr (exp, target, tmode, modifier)
 
     case PLACEHOLDER_EXPR:
       {
-       tree placeholder_expr;
-
-       /* If there is an object on the head of the placeholder list,
-          see if some object in it of type TYPE or a pointer to it.  For
-          further information, see tree.def.  */
-       for (placeholder_expr = placeholder_list;
-            placeholder_expr != 0;
-            placeholder_expr = TREE_CHAIN (placeholder_expr))
-         {
-           tree need_type = TYPE_MAIN_VARIANT (type);
-           tree object = 0;
-           tree old_list = placeholder_list;
-           tree elt;
-
-           /* Find the outermost reference that is of the type we want.
-              If none, see if any object has a type that is a pointer to
-              the type we want.  */
-           for (elt = TREE_PURPOSE (placeholder_expr);
-                elt != 0 && object == 0;
-                elt
-                = ((TREE_CODE (elt) == COMPOUND_EXPR
-                    || TREE_CODE (elt) == COND_EXPR)
-                   ? TREE_OPERAND (elt, 1)
-                   : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
-                      || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
-                      || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
-                      || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
-                   ? TREE_OPERAND (elt, 0) : 0))
-             if (TYPE_MAIN_VARIANT (TREE_TYPE (elt)) == need_type)
-               object = elt;
-
-           for (elt = TREE_PURPOSE (placeholder_expr);
-                elt != 0 && object == 0;
-                elt
-                = ((TREE_CODE (elt) == COMPOUND_EXPR
-                    || TREE_CODE (elt) == COND_EXPR)
-                   ? TREE_OPERAND (elt, 1)
-                   : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
-                      || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
-                      || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
-                      || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
-                   ? TREE_OPERAND (elt, 0) : 0))
-             if (POINTER_TYPE_P (TREE_TYPE (elt))
-                 && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (elt)))
-                     == need_type))
-               object = build1 (INDIRECT_REF, need_type, elt);
-
-           if (object != 0)
-             {
-               /* Expand this object skipping the list entries before
-                  it was found in case it is also a PLACEHOLDER_EXPR.
-                  In that case, we want to translate it using subsequent
-                  entries.  */
-               placeholder_list = TREE_CHAIN (placeholder_expr);
-               temp = expand_expr (object, original_target, tmode,
-                                   ro_modifier);
-               placeholder_list = old_list;
-               return temp;
-             }
-         }
+       tree old_list = placeholder_list;
+       tree placeholder_expr = 0;
+
+       exp = find_placeholder (exp, &placeholder_expr);
+       if (exp == 0)
+         abort ();
+
+       placeholder_list = TREE_CHAIN (placeholder_expr);
+       temp = expand_expr (exp, original_target, tmode, ro_modifier);
+       placeholder_list = old_list;
+       return temp;
       }
 
       /* We can't find the object or there was a missing WITH_RECORD_EXPR.  */
@@ -6637,7 +6619,7 @@ expand_expr (exp, target, tmode, modifier)
     case LABELED_BLOCK_EXPR:
       if (LABELED_BLOCK_BODY (exp))
        expand_expr_stmt (LABELED_BLOCK_BODY (exp));
-      /* Should perhaps use expand_label, but this is simpler and safer. */
+      /* Should perhaps use expand_label, but this is simpler and safer.  */
       do_pending_stack_adjust ();
       emit_label (label_rtx (LABELED_BLOCK_LABEL (exp)));
       return const0_rtx;
@@ -6736,13 +6718,9 @@ expand_expr (exp, target, tmode, modifier)
 
          if (modifier != EXPAND_CONST_ADDRESS
              && modifier != EXPAND_INITIALIZER
-             && modifier != EXPAND_SUM
-             && (! memory_address_p (GET_MODE (constructor),
-                                     XEXP (constructor, 0))
-                 || (flag_force_addr
-                     && GET_CODE (XEXP (constructor, 0)) != REG)))
-           constructor = change_address (constructor, VOIDmode,
-                                         XEXP (constructor, 0));
+             && modifier != EXPAND_SUM)
+           constructor = validize_mem (constructor);
+
          return constructor;
        }
       else
@@ -6758,7 +6736,7 @@ expand_expr (exp, target, tmode, modifier)
                                                       * TYPE_QUAL_CONST))),
                             TREE_ADDRESSABLE (exp), 1, 1);
 
-         store_constructor (exp, target, TYPE_ALIGN (TREE_TYPE (exp)), 0,
+         store_constructor (exp, target, 0,
                             int_size_in_bytes (TREE_TYPE (exp)));
          return target;
        }
@@ -6805,13 +6783,6 @@ expand_expr (exp, target, tmode, modifier)
        temp = gen_rtx_MEM (mode, op0);
        set_mem_attributes (temp, exp, 0);
 
-       /* It is incorrect to set RTX_UNCHANGING_P from TREE_READONLY
-          here, because, in C and C++, the fact that a location is accessed
-          through a pointer to const does not mean that the value there can
-          never change.  Languages where it can never change should
-          also set TREE_STATIC.  */
-       RTX_UNCHANGING_P (temp) = TREE_READONLY (exp) & TREE_STATIC (exp);
-
        /* If we are writing to this object and its type is a record with
           readonly fields, we must mark it as readonly so it will
           conflict with readonly references to those fields.  */
@@ -6902,7 +6873,7 @@ expand_expr (exp, target, tmode, modifier)
                         elem = TREE_CHAIN (elem))
                      ;
 
-                   if (elem && !TREE_SIDE_EFFECTS (elem))
+                   if (elem && !TREE_SIDE_EFFECTS (TREE_VALUE (elem)))
                      return expand_expr (fold (TREE_VALUE (elem)), target,
                                          tmode, ro_modifier);
                  }
@@ -6988,10 +6959,9 @@ expand_expr (exp, target, tmode, modifier)
        HOST_WIDE_INT bitsize, bitpos;
        tree offset;
        int volatilep = 0;
-       unsigned int alignment;
        tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
-                                       &mode1, &unsignedp, &volatilep,
-                                       &alignment);
+                                       &mode1, &unsignedp, &volatilep);
+       rtx orig_op0;
 
        /* If we got back the original object, something is wrong.  Perhaps
           we are evaluating an expression too early.  In any event, don't
@@ -7003,15 +6973,16 @@ expand_expr (exp, target, tmode, modifier)
           computation, since it will need a temporary and TARGET is known
           to have to do.  This occurs in unchecked conversion in Ada.  */
 
-       op0 = expand_expr (tem,
-                          (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
-                           && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
-                               != INTEGER_CST)
-                           ? target : NULL_RTX),
-                          VOIDmode,
-                          (modifier == EXPAND_INITIALIZER
-                           || modifier == EXPAND_CONST_ADDRESS)
-                          ? modifier : EXPAND_NORMAL);
+       orig_op0 = op0
+         = expand_expr (tem,
+                        (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
+                         && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
+                             != INTEGER_CST)
+                         ? target : NULL_RTX),
+                        VOIDmode,
+                        (modifier == EXPAND_INITIALIZER
+                         || modifier == EXPAND_CONST_ADDRESS)
+                        ? modifier : EXPAND_NORMAL);
 
        /* If this is a constant, put it into a register if it is a
           legitimate constant and OFFSET is 0 and memory if it isn't.  */
@@ -7051,7 +7022,6 @@ expand_expr (exp, target, tmode, modifier)
                                               | TYPE_QUAL_CONST));
                    rtx memloc = assign_temp (nt, 1, 1, 1);
 
-                   mark_temp_addr_taken (memloc);
                    emit_move_insn (memloc, op0);
                    op0 = memloc;
                  }
@@ -7061,13 +7031,12 @@ expand_expr (exp, target, tmode, modifier)
              abort ();
 
            if (GET_MODE (offset_rtx) != ptr_mode)
-             {
+             offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
+
 #ifdef POINTERS_EXTEND_UNSIGNED
-               offset_rtx = convert_memory_address (ptr_mode, offset_rtx);
-#else
-               offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
+           if (GET_MODE (offset_rtx) != Pmode)
+             offset_rtx = convert_memory_address (Pmode, offset_rtx);
 #endif
-             }
 
            /* A constant address in OP0 can have VOIDmode, we must not try
               to call force_reg for that case.  Avoid that case.  */
@@ -7077,31 +7046,30 @@ expand_expr (exp, target, tmode, modifier)
                && bitsize != 0
                && (bitpos % bitsize) == 0
                && (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
-               && alignment == GET_MODE_ALIGNMENT (mode1))
+               && MEM_ALIGN (op0) == GET_MODE_ALIGNMENT (mode1))
              {
-               rtx temp = change_address (op0, mode1,
-                                          plus_constant (XEXP (op0, 0),
-                                                         (bitpos /
-                                                          BITS_PER_UNIT)));
+               rtx temp = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
+
                if (GET_CODE (XEXP (temp, 0)) == REG)
                  op0 = temp;
                else
-                 op0 = change_address (op0, mode1,
-                                       force_reg (GET_MODE (XEXP (temp, 0)),
-                                                  XEXP (temp, 0)));
+                 op0 = (replace_equiv_address
+                        (op0,
+                         force_reg (GET_MODE (XEXP (temp, 0)),
+                                    XEXP (temp, 0))));
                bitpos = 0;
              }
 
-           op0 = change_address (op0, VOIDmode,
-                                 gen_rtx_PLUS (ptr_mode, XEXP (op0, 0),
-                                               force_reg (ptr_mode,
-                                                          offset_rtx)));
+           op0 = offset_address (op0, offset_rtx,
+                                 highest_pow2_factor (offset));
          }
 
        /* Don't forget about volatility even if this is a bitfield.  */
        if (GET_CODE (op0) == MEM && volatilep && ! MEM_VOLATILE_P (op0))
          {
-           op0 = copy_rtx (op0);
+           if (op0 == orig_op0)
+             op0 = copy_rtx (op0);
+
            MEM_VOLATILE_P (op0) = 1;
          }
 
@@ -7143,11 +7111,13 @@ expand_expr (exp, target, tmode, modifier)
            || GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
            || (mode1 != BLKmode && ! direct_load[(int) mode1]
                && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
-               && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
+               && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT
+               && modifier != EXPAND_CONST_ADDRESS
+               && modifier != EXPAND_INITIALIZER)
            /* If the field isn't aligned enough to fetch as a memref,
               fetch it as a bit field.  */
            || (mode1 != BLKmode
-               && SLOW_UNALIGNED_ACCESS (mode1, alignment)
+               && SLOW_UNALIGNED_ACCESS (mode1, MEM_ALIGN (op0))
                && ((TYPE_ALIGN (TREE_TYPE (tem))
                     < GET_MODE_ALIGNMENT (mode))
                    || (bitpos % GET_MODE_ALIGNMENT (mode) != 0)))
@@ -7158,11 +7128,7 @@ expand_expr (exp, target, tmode, modifier)
                && (TREE_CODE (TYPE_SIZE (TREE_TYPE (exp)))
                    == INTEGER_CST)
                && 0 != compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)),
-                                         bitsize))
-           || (mode == BLKmode
-               && SLOW_UNALIGNED_ACCESS (mode, alignment)
-               && (TYPE_ALIGN (type) > alignment
-                   || bitpos % TYPE_ALIGN (type) != 0)))
+                                         bitsize)))
          {
            enum machine_mode ext_mode = mode;
 
@@ -7181,17 +7147,13 @@ expand_expr (exp, target, tmode, modifier)
                    || bitpos % BITS_PER_UNIT != 0)
                  abort ();
 
-               op0 = change_address (op0, VOIDmode,
-                                     plus_constant (XEXP (op0, 0),
-                                                    bitpos / BITS_PER_UNIT));
+               op0 = adjust_address (op0, VOIDmode, bitpos / BITS_PER_UNIT);
                if (target == 0)
                  target = assign_temp (type, 0, 1, 1);
 
                emit_block_move (target, op0,
-                                bitsize == -1 ? expr_size  (exp)
-                                : GEN_INT ((bitsize + BITS_PER_UNIT - 1)
-                                           / BITS_PER_UNIT),
-                                BITS_PER_UNIT);
+                                GEN_INT ((bitsize + BITS_PER_UNIT - 1)
+                                         / BITS_PER_UNIT));
 
                return target;
              }
@@ -7199,11 +7161,10 @@ expand_expr (exp, target, tmode, modifier)
            op0 = validize_mem (op0);
 
            if (GET_CODE (op0) == MEM && GET_CODE (XEXP (op0, 0)) == REG)
-             mark_reg_pointer (XEXP (op0, 0), alignment);
+             mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
 
            op0 = extract_bit_field (op0, bitsize, bitpos,
                                     unsignedp, target, ext_mode, ext_mode,
-                                    alignment,
                                     int_size_in_bytes (TREE_TYPE (tem)));
 
            /* If the result is a record type and BITSIZE is narrower than
@@ -7239,22 +7200,16 @@ expand_expr (exp, target, tmode, modifier)
        /* Get a reference to just this component.  */
        if (modifier == EXPAND_CONST_ADDRESS
            || modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
-         {
-           rtx new = gen_rtx_MEM (mode1,
-                                  plus_constant (XEXP (op0, 0),
-                                                 (bitpos / BITS_PER_UNIT)));
-
-           MEM_COPY_ATTRIBUTES (new, op0);
-           op0 = new;
-         }
+         op0 = adjust_address_nv (op0, mode1, bitpos / BITS_PER_UNIT);
        else
-         op0 = change_address (op0, mode1,
-                               plus_constant (XEXP (op0, 0),
-                                              (bitpos / BITS_PER_UNIT)));
+         op0 = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
+
+       if (op0 == orig_op0)
+         op0 = copy_rtx (op0);
 
        set_mem_attributes (op0, exp, 0);
        if (GET_CODE (XEXP (op0, 0)) == REG)
-         mark_reg_pointer (XEXP (op0, 0), alignment);
+         mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
 
        MEM_VOLATILE_P (op0) |= volatilep;
        if (mode == mode1 || mode1 == BLKmode || mode1 == tmode
@@ -7268,6 +7223,43 @@ expand_expr (exp, target, tmode, modifier)
        return target;
       }
 
+    case VTABLE_REF:
+      {
+       rtx insn, before = get_last_insn (), vtbl_ref;
+
+       /* Evaluate the interior expression.  */
+       subtarget = expand_expr (TREE_OPERAND (exp, 0), target,
+                                tmode, modifier);
+
+       /* Get or create an instruction off which to hang a note.  */
+       if (REG_P (subtarget))
+         {
+           target = subtarget;
+           insn = get_last_insn ();
+           if (insn == before)
+             abort ();
+           if (! INSN_P (insn))
+             insn = prev_nonnote_insn (insn);
+         }
+       else
+         {
+           target = gen_reg_rtx (GET_MODE (subtarget));
+           insn = emit_move_insn (target, subtarget);
+         }
+
+       /* Collect the data for the note.  */
+       vtbl_ref = XEXP (DECL_RTL (TREE_OPERAND (exp, 1)), 0);
+       vtbl_ref = plus_constant (vtbl_ref,
+                                 tree_low_cst (TREE_OPERAND (exp, 2), 0));
+       /* Discard the initial CONST that was added.  */
+       vtbl_ref = XEXP (vtbl_ref, 0);
+
+       REG_NOTES (insn)
+         = gen_rtx_EXPR_LIST (REG_VTABLE_REF, vtbl_ref, REG_NOTES (insn));
+
+       return target;
+      }
+
       /* Intended for a reference to a buffer of a file-object in Pascal.
         But it's not certain that a special tree code will really be
         necessary for these.  INDIRECT_REF might work for them.  */
@@ -7324,17 +7316,13 @@ expand_expr (exp, target, tmode, modifier)
 
        if (! (GET_CODE (index_val) == CONST_INT
               && GET_CODE (lo_r) == CONST_INT))
-         {
-           emit_cmp_and_jump_insns (index_val, lo_r, LT, NULL_RTX,
-                                    GET_MODE (index_val), iunsignedp, 0, op1);
-         }
+         emit_cmp_and_jump_insns (index_val, lo_r, LT, NULL_RTX,
+                                  GET_MODE (index_val), iunsignedp, op1);
 
        if (! (GET_CODE (index_val) == CONST_INT
               && GET_CODE (hi_r) == CONST_INT))
-         {
-           emit_cmp_and_jump_insns (index_val, hi_r, GT, NULL_RTX,
-                                    GET_MODE (index_val), iunsignedp, 0, op1);
-         }
+         emit_cmp_and_jump_insns (index_val, hi_r, GT, NULL_RTX,
+                                  GET_MODE (index_val), iunsignedp, op1);
 
        /* Calculate the element number of bit zero in the first word
           of the set.  */
@@ -7380,16 +7368,16 @@ expand_expr (exp, target, tmode, modifier)
       }
 
     case WITH_CLEANUP_EXPR:
-      if (RTL_EXPR_RTL (exp) == 0)
+      if (WITH_CLEANUP_EXPR_RTL (exp) == 0)
        {
-         RTL_EXPR_RTL (exp)
+         WITH_CLEANUP_EXPR_RTL (exp)
            = expand_expr (TREE_OPERAND (exp, 0), target, tmode, ro_modifier);
-         expand_decl_cleanup (NULL_TREE, TREE_OPERAND (exp, 2));
+         expand_decl_cleanup (NULL_TREE, TREE_OPERAND (exp, 1));
 
          /* That's it for this cleanup.  */
-         TREE_OPERAND (exp, 2) = 0;
+         TREE_OPERAND (exp, 1) = 0;
        }
-      return RTL_EXPR_RTL (exp);
+      return WITH_CLEANUP_EXPR_RTL (exp);
 
     case CLEANUP_POINT_EXPR:
       {
@@ -7450,7 +7438,7 @@ expand_expr (exp, target, tmode, modifier)
          if (GET_CODE (target) == MEM)
            /* Store data into beginning of memory target.  */
            store_expr (TREE_OPERAND (exp, 0),
-                       change_address (target, TYPE_MODE (valtype), 0), 0);
+                       adjust_address (target, TYPE_MODE (valtype), 0), 0);
 
          else if (GET_CODE (target) == REG)
            /* Store this field into a union of the proper type.  */
@@ -7460,8 +7448,7 @@ expand_expr (exp, target, tmode, modifier)
                               * BITS_PER_UNIT),
                              (HOST_WIDE_INT) GET_MODE_BITSIZE (mode)),
                         0, TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
-                        VOIDmode, 0, BITS_PER_UNIT,
-                        int_size_in_bytes (type), 0);
+                        VOIDmode, 0, type, 0);
          else
            abort ();
 
@@ -7715,7 +7702,7 @@ expand_expr (exp, target, tmode, modifier)
         check the second operand.  */
       if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST)
        {
-         register tree t1 = TREE_OPERAND (exp, 0);
+         tree t1 = TREE_OPERAND (exp, 0);
          TREE_OPERAND (exp, 0) = TREE_OPERAND (exp, 1);
          TREE_OPERAND (exp, 1) = t1;
        }
@@ -7846,7 +7833,17 @@ expand_expr (exp, target, tmode, modifier)
       return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
 
     case RDIV_EXPR:
-      this_optab = flodiv_optab;
+      /* Emit a/b as a*(1/b).  Later we may manage CSE the reciprocal saving
+         expensive divide.  If not, combine will rebuild the original
+         computation.  */
+      if (flag_unsafe_math_optimizations && optimize && !optimize_size
+         && !real_onep (TREE_OPERAND (exp, 0)))
+        return expand_expr (build (MULT_EXPR, type, TREE_OPERAND (exp, 0),
+                                  build (RDIV_EXPR, type,
+                                         build_real (type, dconst1),
+                                         TREE_OPERAND (exp, 1))),
+                           target, tmode, unsignedp);
+      this_optab = sdiv_optab;
       goto binop;
 
     case TRUNC_MOD_EXPR:
@@ -7961,7 +7958,7 @@ expand_expr (exp, target, tmode, modifier)
        {
          int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)));
          do_compare_rtx_and_jump (target, op1, code == MAX_EXPR ? GE : LE,
-                                  unsignedp, mode, NULL_RTX, 0, NULL_RTX,
+                                  unsignedp, mode, NULL_RTX, NULL_RTX,
                                   op0);
        }
       emit_move_insn (target, op1);
@@ -8054,7 +8051,7 @@ expand_expr (exp, target, tmode, modifier)
 
          op1 = gen_label_rtx ();
          emit_cmp_and_jump_insns (temp, const0_rtx, EQ, NULL_RTX,
-                                  GET_MODE (temp), unsignedp, 0, op1);
+                                  GET_MODE (temp), unsignedp, op1);
          emit_move_insn (temp, const1_rtx);
          emit_label (op1);
          return temp;
@@ -8205,8 +8202,8 @@ expand_expr (exp, target, tmode, modifier)
                     || GET_CODE (original_target) == REG
                     || TREE_ADDRESSABLE (type))
 #endif
-                && ! (GET_CODE (original_target) == MEM
-                      && MEM_VOLATILE_P (original_target)))
+                && (GET_CODE (original_target) != MEM
+                    || TREE_ADDRESSABLE (type)))
          temp = original_target;
        else if (TREE_ADDRESSABLE (type))
          abort ();
@@ -8495,37 +8492,23 @@ expand_expr (exp, target, tmode, modifier)
       {
        tree lhs = TREE_OPERAND (exp, 0);
        tree rhs = TREE_OPERAND (exp, 1);
-       tree noncopied_parts = 0;
-       tree lhs_type = TREE_TYPE (lhs);
 
        temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
-       if (TYPE_NONCOPIED_PARTS (lhs_type) != 0 && !fixed_type_p (rhs))
-         noncopied_parts
-           = init_noncopied_parts (stabilize_reference (lhs),
-                                   TYPE_NONCOPIED_PARTS (lhs_type));
-
-       while (noncopied_parts != 0)
-         {
-           expand_assignment (TREE_VALUE (noncopied_parts),
-                              TREE_PURPOSE (noncopied_parts), 0, 0);
-           noncopied_parts = TREE_CHAIN (noncopied_parts);
-         }
        return temp;
       }
 
     case MODIFY_EXPR:
       {
        /* If lhs is complex, expand calls in rhs before computing it.
-          That's so we don't compute a pointer and save it over a call.
-          If lhs is simple, compute it first so we can give it as a
-          target if the rhs is just a call.  This avoids an extra temp and copy
-          and that prevents a partial-subsumption which makes bad code.
-          Actually we could treat component_ref's of vars like vars.  */
+          That's so we don't compute a pointer and save it over a
+          call.  If lhs is simple, compute it first so we can give it
+          as a target if the rhs is just a call.  This avoids an
+          extra temp and copy and that prevents a partial-subsumption
+          which makes bad code.  Actually we could treat
+          component_ref's of vars like vars.  */
 
        tree lhs = TREE_OPERAND (exp, 0);
        tree rhs = TREE_OPERAND (exp, 1);
-       tree noncopied_parts = 0;
-       tree lhs_type = TREE_TYPE (lhs);
 
        temp = 0;
 
@@ -8561,19 +8544,8 @@ expand_expr (exp, target, tmode, modifier)
            return const0_rtx;
          }
 
-       if (TYPE_NONCOPIED_PARTS (lhs_type) != 0
-           && ! (fixed_type_p (lhs) && fixed_type_p (rhs)))
-         noncopied_parts
-           = save_noncopied_parts (stabilize_reference (lhs),
-                                   TYPE_NONCOPIED_PARTS (lhs_type));
-
        temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
-       while (noncopied_parts != 0)
-         {
-           expand_assignment (TREE_PURPOSE (noncopied_parts),
-                              TREE_VALUE (noncopied_parts), 0, 0);
-           noncopied_parts = TREE_CHAIN (noncopied_parts);
-         }
+       
        return temp;
       }
 
@@ -8594,10 +8566,6 @@ expand_expr (exp, target, tmode, modifier)
       return expand_increment (exp, ! ignore, ignore);
 
     case ADDR_EXPR:
-      /* If nonzero, TEMP will be set to the address of something that might
-        be a MEM corresponding to a stack slot.  */
-      temp = 0;
-
       /* Are we taking the address of a nested function?  */
       if (TREE_CODE (TREE_OPERAND (exp, 0)) == FUNCTION_DECL
          && decl_function_context (TREE_OPERAND (exp, 0)) != 0
@@ -8611,6 +8579,14 @@ expand_expr (exp, target, tmode, modifier)
         return a zero.  */
       else if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK)
        return const0_rtx;
+      /* If we are taking the address of a constant and are at the
+        top level, we have to use output_constant_def since we can't
+        call force_const_mem at top level.  */
+      else if (cfun == 0
+              && (TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR
+                  || (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0)))
+                      == 'c')))
+       op0 = XEXP (output_constant_def (TREE_OPERAND (exp, 0), 0), 0);
       else
        {
          /* We make sure to pass const0_rtx down if we came in with
@@ -8637,48 +8613,60 @@ expand_expr (exp, target, tmode, modifier)
          if (CONSTANT_P (op0))
            op0 = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
                                   op0);
-         else if (GET_CODE (op0) == MEM)
-           {
-             mark_temp_addr_taken (op0);
-             temp = XEXP (op0, 0);
-           }
-
          else if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
                   || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF
                   || GET_CODE (op0) == PARALLEL)
            {
-             /* If this object is in a register, it must be not
-                be BLKmode.  */
+             /* If this object is in a register, it must can't be BLKmode.  */
              tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
              tree nt = build_qualified_type (inner_type,
                                              (TYPE_QUALS (inner_type)
                                               | TYPE_QUAL_CONST));
              rtx memloc = assign_temp (nt, 1, 1, 1);
 
-             mark_temp_addr_taken (memloc);
              if (GET_CODE (op0) == PARALLEL)
                /* Handle calls that pass values in multiple non-contiguous
                   locations.  The Irix 6 ABI has examples of this.  */
-               emit_group_store (memloc, op0,
-                                 int_size_in_bytes (inner_type),
-                                 TYPE_ALIGN (inner_type));
+               emit_group_store (memloc, op0, int_size_in_bytes (inner_type));
              else
                emit_move_insn (memloc, op0);
+
              op0 = memloc;
            }
 
          if (GET_CODE (op0) != MEM)
            abort ();
 
+         mark_temp_addr_taken (op0);
          if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
            {
-             temp = XEXP (op0, 0);
+             op0 = XEXP (op0, 0);
 #ifdef POINTERS_EXTEND_UNSIGNED
-             if (GET_MODE (temp) == Pmode && GET_MODE (temp) != mode
+             if (GET_MODE (op0) == Pmode && GET_MODE (op0) != mode
                  && mode == ptr_mode)
-               temp = convert_memory_address (ptr_mode, temp);
+               op0 = convert_memory_address (ptr_mode, op0);
 #endif
-             return temp;
+             return op0;
+           }
+
+         /* If OP0 is not aligned as least as much as the type requires,
+            we need to make a temporary, copy OP0 to it, and take the
+            address of the temporary.  */
+         if (GET_MODE (op0) == BLKmode
+             && expr_align (TREE_OPERAND (exp, 0)) > MEM_ALIGN (op0))
+           {
+             tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
+             rtx new
+               = assign_stack_temp_for_type
+                 (TYPE_MODE (inner_type),
+                  MEM_SIZE (op0) ? INTVAL (MEM_SIZE (op0))
+                  : int_size_in_bytes (TREE_TYPE (inner_type)),
+                  1, build_qualified_type (inner_type,
+                                           (TYPE_QUALS (inner_type)
+                                            | TYPE_QUAL_CONST)));
+
+             emit_block_move (new, op0, expr_size (TREE_OPERAND (exp, 0)));
+             op0 = new;
            }
 
          op0 = force_operand (XEXP (op0, 0), target);
@@ -8691,11 +8679,6 @@ expand_expr (exp, target, tmode, modifier)
          && ! REG_USERVAR_P (op0))
        mark_reg_pointer (op0, TYPE_ALIGN (TREE_TYPE (type)));
 
-      /* If we might have had a temp slot, add an equivalent address
-        for it.  */
-      if (temp != 0)
-       update_temp_slot_address (temp, op0);
-
 #ifdef POINTERS_EXTEND_UNSIGNED
       if (GET_MODE (op0) == Pmode && GET_MODE (op0) != mode
          && mode == ptr_mode)
@@ -8851,6 +8834,11 @@ expand_expr (exp, target, tmode, modifier)
     case EXC_PTR_EXPR:
       return get_exception_pointer (cfun);
 
+    case FDESC_EXPR:
+      /* Function descriptors are not valid except for as
+        initialization constants, and should not be expanded.  */
+      abort ();
+
     default:
       return (*lang_expand_expr) (exp, original_target, tmode, modifier);
     }
@@ -8870,321 +8858,6 @@ expand_expr (exp, target, tmode, modifier)
   return temp;
 }
 \f
-/* Similar to expand_expr, except that we don't specify a target, target
-   mode, or modifier and we return the alignment of the inner type.  This is
-   used in cases where it is not necessary to align the result to the
-   alignment of its type as long as we know the alignment of the result, for
-   example for comparisons of BLKmode values.  */
-
-static rtx
-expand_expr_unaligned (exp, palign)
-     register tree exp;
-     unsigned int *palign;
-{
-  register rtx op0;
-  tree type = TREE_TYPE (exp);
-  register enum machine_mode mode = TYPE_MODE (type);
-
-  /* Default the alignment we return to that of the type.  */
-  *palign = TYPE_ALIGN (type);
-
-  /* The only cases in which we do anything special is if the resulting mode
-     is BLKmode.  */
-  if (mode != BLKmode)
-    return expand_expr (exp, NULL_RTX, VOIDmode, EXPAND_NORMAL);
-
-  switch (TREE_CODE (exp))
-    {
-    case CONVERT_EXPR:
-    case NOP_EXPR:
-    case NON_LVALUE_EXPR:
-      /* Conversions between BLKmode values don't change the underlying
-         alignment or value.  */
-      if (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == BLKmode)
-       return expand_expr_unaligned (TREE_OPERAND (exp, 0), palign);
-      break;
-
-    case ARRAY_REF:
-      /* Much of the code for this case is copied directly from expand_expr.
-        We need to duplicate it here because we will do something different
-        in the fall-through case, so we need to handle the same exceptions
-        it does.  */
-      {
-       tree array = TREE_OPERAND (exp, 0);
-       tree domain = TYPE_DOMAIN (TREE_TYPE (array));
-       tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
-       tree index = convert (sizetype, TREE_OPERAND (exp, 1));
-       HOST_WIDE_INT i;
-
-       if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) != ARRAY_TYPE)
-         abort ();
-
-       /* Optimize the special-case of a zero lower bound.
-
-          We convert the low_bound to sizetype to avoid some problems
-          with constant folding.  (E.g. suppose the lower bound is 1,
-          and its mode is QI.  Without the conversion,  (ARRAY
-          +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
-          +INDEX), which becomes (ARRAY+255+INDEX).  Oops!)  */
-
-       if (! integer_zerop (low_bound))
-         index = size_diffop (index, convert (sizetype, low_bound));
-
-       /* If this is a constant index into a constant array,
-          just get the value from the array.  Handle both the cases when
-          we have an explicit constructor and when our operand is a variable
-          that was declared const.  */
-
-       if (TREE_CODE (array) == CONSTRUCTOR && ! TREE_SIDE_EFFECTS (array)
-           && host_integerp (index, 0)
-           && 0 > compare_tree_int (index,
-                                    list_length (CONSTRUCTOR_ELTS
-                                                 (TREE_OPERAND (exp, 0)))))
-         {
-           tree elem;
-
-           for (elem = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)),
-                i = tree_low_cst (index, 0);
-                elem != 0 && i != 0; i--, elem = TREE_CHAIN (elem))
-             ;
-
-           if (elem)
-             return expand_expr_unaligned (fold (TREE_VALUE (elem)), palign);
-         }
-
-       else if (optimize >= 1
-                && TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
-                && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
-                && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK)
-         {
-           if (TREE_CODE (index) == INTEGER_CST)
-             {
-               tree init = DECL_INITIAL (array);
-
-               if (TREE_CODE (init) == CONSTRUCTOR)
-                 {
-                   tree elem;
-
-                   for (elem = CONSTRUCTOR_ELTS (init);
-                        ! tree_int_cst_equal (TREE_PURPOSE (elem), index);
-                        elem = TREE_CHAIN (elem))
-                     ;
-
-                   if (elem)
-                     return expand_expr_unaligned (fold (TREE_VALUE (elem)),
-                                                   palign);
-                 }
-             }
-         }
-      }
-      /* Fall through.  */
-
-    case COMPONENT_REF:
-    case BIT_FIELD_REF:
-    case ARRAY_RANGE_REF:
-      /* If the operand is a CONSTRUCTOR, we can just extract the
-        appropriate field if it is present.  Don't do this if we have
-        already written the data since we want to refer to that copy
-        and varasm.c assumes that's what we'll do.  */
-      if (TREE_CODE (exp) == COMPONENT_REF
-         && TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR
-         && TREE_CST_RTL (TREE_OPERAND (exp, 0)) == 0)
-       {
-         tree elt;
-
-         for (elt = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); elt;
-              elt = TREE_CHAIN (elt))
-           if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1))
-             /* Note that unlike the case in expand_expr, we know this is
-                BLKmode and hence not an integer.  */
-             return expand_expr_unaligned (TREE_VALUE (elt), palign);
-       }
-
-      {
-       enum machine_mode mode1;
-       HOST_WIDE_INT bitsize, bitpos;
-       tree offset;
-       int volatilep = 0;
-       unsigned int alignment;
-       int unsignedp;
-       tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
-                                       &mode1, &unsignedp, &volatilep,
-                                       &alignment);
-
-       /* If we got back the original object, something is wrong.  Perhaps
-          we are evaluating an expression too early.  In any event, don't
-          infinitely recurse.  */
-       if (tem == exp)
-         abort ();
-
-       op0 = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_NORMAL);
-
-       /* If this is a constant, put it into a register if it is a
-          legitimate constant and OFFSET is 0 and memory if it isn't.  */
-       if (CONSTANT_P (op0))
-         {
-           enum machine_mode inner_mode = TYPE_MODE (TREE_TYPE (tem));
-
-           if (inner_mode != BLKmode && LEGITIMATE_CONSTANT_P (op0)
-               && offset == 0)
-             op0 = force_reg (inner_mode, op0);
-           else
-             op0 = validize_mem (force_const_mem (inner_mode, op0));
-         }
-
-       if (offset != 0)
-         {
-           rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
-
-           /* If this object is in a register, put it into memory.
-              This case can't occur in C, but can in Ada if we have
-              unchecked conversion of an expression from a scalar type to
-              an array or record type.  */
-           if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
-               || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
-             {
-               tree nt = build_qualified_type (TREE_TYPE (tem),
-                                               (TYPE_QUALS (TREE_TYPE (tem))
-                                                | TYPE_QUAL_CONST));
-               rtx memloc = assign_temp (nt, 1, 1, 1);
-
-               mark_temp_addr_taken (memloc);
-               emit_move_insn (memloc, op0);
-               op0 = memloc;
-             }
-
-           if (GET_CODE (op0) != MEM)
-             abort ();
-
-           if (GET_MODE (offset_rtx) != ptr_mode)
-             {
-#ifdef POINTERS_EXTEND_UNSIGNED
-               offset_rtx = convert_memory_address (ptr_mode, offset_rtx);
-#else
-               offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
-#endif
-             }
-
-           op0 = change_address (op0, VOIDmode,
-                                 gen_rtx_PLUS (ptr_mode, XEXP (op0, 0),
-                                               force_reg (ptr_mode,
-                                                          offset_rtx)));
-         }
-
-       /* Don't forget about volatility even if this is a bitfield.  */
-       if (GET_CODE (op0) == MEM && volatilep && ! MEM_VOLATILE_P (op0))
-         {
-           op0 = copy_rtx (op0);
-           MEM_VOLATILE_P (op0) = 1;
-         }
-
-       /* Check the access.  */
-       if (current_function_check_memory_usage && GET_CODE (op0) == MEM)
-         {
-           rtx to;
-           int size;
-
-           to = plus_constant (XEXP (op0, 0), (bitpos / BITS_PER_UNIT));
-           size = (bitpos % BITS_PER_UNIT) + bitsize + BITS_PER_UNIT - 1;
-
-           /* Check the access right of the pointer.  */
-           in_check_memory_usage = 1;
-           if (size > BITS_PER_UNIT)
-             emit_library_call (chkr_check_addr_libfunc,
-                                LCT_CONST_MAKE_BLOCK, VOIDmode, 3,
-                                to, ptr_mode, GEN_INT (size / BITS_PER_UNIT),
-                                TYPE_MODE (sizetype),
-                                GEN_INT (MEMORY_USE_RO),
-                                TYPE_MODE (integer_type_node));
-           in_check_memory_usage = 0;
-         }
-
-       /* In cases where an aligned union has an unaligned object
-          as a field, we might be extracting a BLKmode value from
-          an integer-mode (e.g., SImode) object.  Handle this case
-          by doing the extract into an object as wide as the field
-          (which we know to be the width of a basic mode), then
-          storing into memory, and changing the mode to BLKmode.
-          If we ultimately want the address (EXPAND_CONST_ADDRESS or
-          EXPAND_INITIALIZER), then we must not copy to a temporary.  */
-       if (mode1 == VOIDmode
-           || GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
-           || (SLOW_UNALIGNED_ACCESS (mode1, alignment)
-               && (TYPE_ALIGN (type) > alignment
-                   || bitpos % TYPE_ALIGN (type) != 0)))
-         {
-           enum machine_mode ext_mode = mode_for_size (bitsize, MODE_INT, 1);
-
-           if (ext_mode == BLKmode)
-             {
-               /* In this case, BITPOS must start at a byte boundary.  */
-               if (GET_CODE (op0) != MEM
-                   || bitpos % BITS_PER_UNIT != 0)
-                 abort ();
-
-               op0 = change_address (op0, VOIDmode,
-                                     plus_constant (XEXP (op0, 0),
-                                                    bitpos / BITS_PER_UNIT));
-             }
-           else
-             {
-               tree nt = build_qualified_type (type_for_mode (ext_mode, 0),
-                                               TYPE_QUAL_CONST);
-               rtx new = assign_temp (nt, 0, 1, 1);
-
-               op0 = extract_bit_field (validize_mem (op0), bitsize, bitpos,
-                                        unsignedp, NULL_RTX, ext_mode,
-                                        ext_mode, alignment,
-                                        int_size_in_bytes (TREE_TYPE (tem)));
-
-               /* If the result is a record type and BITSIZE is narrower than
-                  the mode of OP0, an integral mode, and this is a big endian
-                  machine, we must put the field into the high-order bits.  */
-               if (TREE_CODE (type) == RECORD_TYPE && BYTES_BIG_ENDIAN
-                   && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
-                   && bitsize < GET_MODE_BITSIZE (GET_MODE (op0)))
-                 op0 = expand_shift (LSHIFT_EXPR, GET_MODE (op0), op0,
-                                     size_int (GET_MODE_BITSIZE
-                                               (GET_MODE (op0))
-                                               - bitsize),
-                                     op0, 1);
-
-               emit_move_insn (new, op0);
-               op0 = copy_rtx (new);
-               PUT_MODE (op0, BLKmode);
-             }
-         }
-       else
-         /* Get a reference to just this component.  */
-         op0 = change_address (op0, mode1,
-                               plus_constant (XEXP (op0, 0),
-                                              (bitpos / BITS_PER_UNIT)));
-
-       MEM_ALIAS_SET (op0) = get_alias_set (exp);
-
-       /* Adjust the alignment in case the bit position is not
-          a multiple of the alignment of the inner object.  */
-       while (bitpos % alignment != 0)
-         alignment >>= 1;
-
-       if (GET_CODE (XEXP (op0, 0)) == REG)
-         mark_reg_pointer (XEXP (op0, 0), alignment);
-
-       MEM_IN_STRUCT_P (op0) = 1;
-       MEM_VOLATILE_P (op0) |= volatilep;
-
-       *palign = alignment;
-       return op0;
-      }
-
-    default:
-      break;
-
-    }
-
-  return expand_expr (exp, NULL_RTX, VOIDmode, EXPAND_NORMAL);
-}
-\f
 /* Return the tree node if a ARG corresponds to a string constant or zero
    if it doesn't.  If we return non-zero, set *PTR_OFFSET to the offset
    in bytes within the string that ARG is accessing.  The type of the
@@ -9234,12 +8907,12 @@ string_constant (arg, ptr_offset)
 
 static rtx
 expand_increment (exp, post, ignore)
-     register tree exp;
+     tree exp;
      int post, ignore;
 {
-  register rtx op0, op1;
-  register rtx temp, value;
-  register tree incremented = TREE_OPERAND (exp, 0);
+  rtx op0, op1;
+  rtx temp, value;
+  tree incremented = TREE_OPERAND (exp, 0);
   optab this_optab = add_optab;
   int icode;
   enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
@@ -9268,7 +8941,7 @@ expand_increment (exp, post, ignore)
   /* Compute the operands as RTX.
      Note whether OP0 is the actual lvalue or a copy of it:
      I believe it is a copy iff it is a register or subreg
-     and insns were generated in computing it.   */
+     and insns were generated in computing it.  */
 
   temp = get_last_insn ();
   op0 = expand_expr (incremented, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_RW);
@@ -9399,7 +9072,7 @@ expand_increment (exp, post, ignore)
                      : copy_to_reg (XEXP (op0, 0)));
          rtx temp, result;
 
-         op0 = change_address (op0, VOIDmode, addr);
+         op0 = replace_equiv_address (op0, addr);
          temp = force_reg (GET_MODE (op0), op0);
          if (! (*insn_data[icode].operand[2].predicate) (op1, mode))
            op1 = force_reg (mode, op1);
@@ -9519,7 +9192,7 @@ do_jump (exp, if_false_label, if_true_label)
      tree exp;
      rtx if_false_label, if_true_label;
 {
-  register enum tree_code code = TREE_CODE (exp);
+  enum tree_code code = TREE_CODE (exp);
   /* Some cases need to create a label to jump to
      in order to properly fall through.
      These cases set DROP_THROUGH_LABEL nonzero.  */
@@ -9673,12 +9346,11 @@ do_jump (exp, if_false_label, if_true_label)
        tree type;
        tree offset;
        int volatilep = 0;
-       unsigned int alignment;
 
        /* Get description of this reference.  We don't actually care
           about the underlying object here.  */
        get_inner_reference (exp, &bitsize, &bitpos, &offset, &mode,
-                            &unsignedp, &volatilep, &alignment);
+                            &unsignedp, &volatilep);
 
        type = type_for_size (bitsize, unsignedp);
        if (! SLOW_BYTE_ACCESS
@@ -9705,7 +9377,7 @@ do_jump (exp, if_false_label, if_true_label)
 
       else
        {
-         register rtx label1 = gen_label_rtx ();
+         rtx label1 = gen_label_rtx ();
          drop_through_label = gen_label_rtx ();
 
          do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX);
@@ -9980,7 +9652,7 @@ do_jump (exp, if_false_label, if_true_label)
       else if (GET_MODE (temp) != VOIDmode)
        do_compare_rtx_and_jump (temp, CONST0_RTX (GET_MODE (temp)),
                                 NE, TREE_UNSIGNED (TREE_TYPE (exp)),
-                                GET_MODE (temp), NULL_RTX, 0,
+                                GET_MODE (temp), NULL_RTX,
                                 if_false_label, if_true_label);
       else
        abort ();
@@ -10055,12 +9727,12 @@ do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true
 
       /* All but high-order word must be compared as unsigned.  */
       do_compare_rtx_and_jump (op0_word, op1_word, GT,
-                              (unsignedp || i > 0), word_mode, NULL_RTX, 0,
+                              (unsignedp || i > 0), word_mode, NULL_RTX,
                               NULL_RTX, if_true_label);
 
       /* Consider lower words only if these are equal.  */
       do_compare_rtx_and_jump (op0_word, op1_word, NE, unsignedp, word_mode,
-                              NULL_RTX, 0, NULL_RTX, if_false_label);
+                              NULL_RTX, NULL_RTX, if_false_label);
     }
 
   if (if_false_label)
@@ -10091,8 +9763,7 @@ do_jump_by_parts_equality (exp, if_false_label, if_true_label)
     do_compare_rtx_and_jump (operand_subword_force (op0, i, mode),
                             operand_subword_force (op1, i, mode),
                             EQ, TREE_UNSIGNED (TREE_TYPE (exp)),
-                            word_mode, NULL_RTX, 0, if_false_label,
-                            NULL_RTX);
+                            word_mode, NULL_RTX, if_false_label, NULL_RTX);
 
   if (if_true_label)
     emit_jump (if_true_label);
@@ -10129,7 +9800,7 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
   if (part != 0)
     {
       do_compare_rtx_and_jump (part, const0_rtx, EQ, 1, word_mode,
-                              NULL_RTX, 0, if_false_label, if_true_label);
+                              NULL_RTX, if_false_label, if_true_label);
 
       return;
     }
@@ -10140,7 +9811,7 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
 
   for (i = 0; i < nwords; i++)
     do_compare_rtx_and_jump (operand_subword_force (op0, i, GET_MODE (op0)),
-                            const0_rtx, EQ, 1, word_mode, NULL_RTX, 0,
+                            const0_rtx, EQ, 1, word_mode, NULL_RTX,
                             if_false_label, NULL_RTX);
 
   if (if_true_label)
@@ -10159,19 +9830,15 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
    things pushed on the stack that aren't yet used.
 
    If MODE is BLKmode, SIZE is an RTX giving the size of the objects being
-   compared.
-
-   If ALIGN is non-zero, it is the alignment of this type; if zero, the
-   size of MODE should be used.  */
+   compared.  */
 
 rtx
-compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
-     register rtx op0, op1;
+compare_from_rtx (op0, op1, code, unsignedp, mode, size)
+     rtx op0, op1;
      enum rtx_code code;
      int unsignedp;
      enum machine_mode mode;
      rtx size;
-     unsigned int align;
 {
   rtx tem;
 
@@ -10220,7 +9887,7 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
     }
 #endif
 
-  emit_cmp_insn (op0, op1, code, size, mode, unsignedp, align);
+  emit_cmp_insn (op0, op1, code, size, mode, unsignedp);
 
   return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
 }
@@ -10229,20 +9896,16 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
    The decision as to signed or unsigned comparison must be made by the caller.
 
    If MODE is BLKmode, SIZE is an RTX giving the size of the objects being
-   compared.
-
-   If ALIGN is non-zero, it is the alignment of this type; if zero, the
-   size of MODE should be used.  */
+   compared.  */
 
 void
-do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, size, align,
+do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, size,
                         if_false_label, if_true_label)
-     register rtx op0, op1;
+     rtx op0, op1;
      enum rtx_code code;
      int unsignedp;
      enum machine_mode mode;
      rtx size;
-     unsigned int align;
      rtx if_false_label, if_true_label;
 {
   rtx tem;
@@ -10320,7 +9983,7 @@ do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, size, align,
       if_true_label = gen_label_rtx ();
     }
 
-  emit_cmp_and_jump_insns (op0, op1, code, size, mode, unsignedp, align,
+  emit_cmp_and_jump_insns (op0, op1, code, size, mode, unsignedp,
                           if_true_label);
 
   if (if_false_label)
@@ -10342,23 +10005,22 @@ do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, size, align,
 static void
 do_compare_and_jump (exp, signed_code, unsigned_code, if_false_label,
                     if_true_label)
-     register tree exp;
+     tree exp;
      enum rtx_code signed_code, unsigned_code;
      rtx if_false_label, if_true_label;
 {
-  unsigned int align0, align1;
-  register rtx op0, op1;
-  register tree type;
-  register enum machine_mode mode;
+  rtx op0, op1;
+  tree type;
+  enum machine_mode mode;
   int unsignedp;
   enum rtx_code code;
 
   /* Don't crash if the comparison was erroneous.  */
-  op0 = expand_expr_unaligned (TREE_OPERAND (exp, 0), &align0);
+  op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
   if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK)
     return;
 
-  op1 = expand_expr_unaligned (TREE_OPERAND (exp, 1), &align1);
+  op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
   if (TREE_CODE (TREE_OPERAND (exp, 1)) == ERROR_MARK)
     return;
 
@@ -10410,7 +10072,6 @@ do_compare_and_jump (exp, signed_code, unsigned_code, if_false_label,
   do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode,
                           ((mode == BLKmode)
                            ? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX),
-                          MIN (align0, align1),
                           if_false_label, if_true_label);
 }
 \f
@@ -10689,7 +10350,7 @@ do_store_flag (exp, target, mode, only_cheap)
 
   emit_move_insn (target, invert ? const0_rtx : const1_rtx);
   result = compare_from_rtx (op0, op1, code, unsignedp,
-                            operand_mode, NULL_RTX, 0);
+                            operand_mode, NULL_RTX);
   if (GET_CODE (result) == CONST_INT)
     return (((result == const0_rtx && ! invert)
             || (result != const0_rtx && invert))
@@ -10706,11 +10367,112 @@ do_store_flag (exp, target, mode, only_cheap)
   return target;
 }
 \f
-/* Generate a tablejump instruction (used for switch statements).  */
 
-#ifdef HAVE_tablejump
+/* Stubs in case we haven't got a casesi insn.  */
+#ifndef HAVE_casesi
+# define HAVE_casesi 0
+# define gen_casesi(a, b, c, d, e) (0)
+# define CODE_FOR_casesi CODE_FOR_nothing
+#endif
+
+/* If the machine does not have a case insn that compares the bounds,
+   this means extra overhead for dispatch tables, which raises the
+   threshold for using them.  */
+#ifndef CASE_VALUES_THRESHOLD
+#define CASE_VALUES_THRESHOLD (HAVE_casesi ? 4 : 5)
+#endif /* CASE_VALUES_THRESHOLD */
 
-/* INDEX is the value being switched on, with the lowest value
+unsigned int
+case_values_threshold ()
+{
+  return CASE_VALUES_THRESHOLD;
+}
+
+/* Attempt to generate a casesi instruction.  Returns 1 if successful,
+   0 otherwise (i.e. if there is no casesi instruction).  */
+int
+try_casesi (index_type, index_expr, minval, range,
+           table_label, default_label)
+     tree index_type, index_expr, minval, range;
+     rtx table_label ATTRIBUTE_UNUSED;
+     rtx default_label;
+{
+  enum machine_mode index_mode = SImode;
+  int index_bits = GET_MODE_BITSIZE (index_mode);
+  rtx op1, op2, index;
+  enum machine_mode op_mode;
+
+  if (! HAVE_casesi)
+    return 0;
+
+  /* Convert the index to SImode.  */
+  if (GET_MODE_BITSIZE (TYPE_MODE (index_type)) > GET_MODE_BITSIZE (index_mode))
+    {
+      enum machine_mode omode = TYPE_MODE (index_type);
+      rtx rangertx = expand_expr (range, NULL_RTX, VOIDmode, 0);
+
+      /* We must handle the endpoints in the original mode.  */
+      index_expr = build (MINUS_EXPR, index_type,
+                         index_expr, minval);
+      minval = integer_zero_node;
+      index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+      emit_cmp_and_jump_insns (rangertx, index, LTU, NULL_RTX,
+                              omode, 1, default_label);
+      /* Now we can safely truncate.  */
+      index = convert_to_mode (index_mode, index, 0);
+    }
+  else
+    {
+      if (TYPE_MODE (index_type) != index_mode)
+       {
+         index_expr = convert (type_for_size (index_bits, 0),
+                               index_expr);
+         index_type = TREE_TYPE (index_expr);
+       }
+
+      index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+    }
+  emit_queue ();
+  index = protect_from_queue (index, 0);
+  do_pending_stack_adjust ();
+
+  op_mode = insn_data[(int) CODE_FOR_casesi].operand[0].mode;
+  if (! (*insn_data[(int) CODE_FOR_casesi].operand[0].predicate)
+      (index, op_mode))
+    index = copy_to_mode_reg (op_mode, index);
+
+  op1 = expand_expr (minval, NULL_RTX, VOIDmode, 0);
+
+  op_mode = insn_data[(int) CODE_FOR_casesi].operand[1].mode;
+  op1 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (minval)),
+                      op1, TREE_UNSIGNED (TREE_TYPE (minval)));
+  if (! (*insn_data[(int) CODE_FOR_casesi].operand[1].predicate)
+      (op1, op_mode))
+    op1 = copy_to_mode_reg (op_mode, op1);
+
+  op2 = expand_expr (range, NULL_RTX, VOIDmode, 0);
+
+  op_mode = insn_data[(int) CODE_FOR_casesi].operand[2].mode;
+  op2 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (range)),
+                      op2, TREE_UNSIGNED (TREE_TYPE (range)));
+  if (! (*insn_data[(int) CODE_FOR_casesi].operand[2].predicate)
+      (op2, op_mode))
+    op2 = copy_to_mode_reg (op_mode, op2);
+
+  emit_jump_insn (gen_casesi (index, op1, op2,
+                             table_label, default_label));
+  return 1;
+}
+
+/* Attempt to generate a tablejump instruction; same concept.  */
+#ifndef HAVE_tablejump
+#define HAVE_tablejump 0
+#define gen_tablejump(x, y) (0)
+#endif
+
+/* Subroutine of the next function.
+
+   INDEX is the value being switched on, with the lowest value
    in the table already subtracted.
    MODE is its expected mode (needed if INDEX is constant).
    RANGE is the length of the jump table.
@@ -10719,12 +10481,12 @@ do_store_flag (exp, target, mode, only_cheap)
    DEFAULT_LABEL is a CODE_LABEL rtx to jump to if the
    index value is out of range.  */
 
-void
+static void
 do_tablejump (index, mode, range, table_label, default_label)
      rtx index, range, table_label, default_label;
      enum machine_mode mode;
 {
-  register rtx temp, vector;
+  rtx temp, vector;
 
   /* Do an unsigned comparison (in the proper mode) between the index
      expression and the value which represents the length of the range.
@@ -10735,7 +10497,7 @@ do_tablejump (index, mode, range, table_label, default_label)
      the maximum value of the range.  */
 
   emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, mode, 1,
-                          0, default_label);
+                          default_label);
 
   /* If index is in range, it must fit in Pmode.
      Convert to Pmode so we can index with it.  */
@@ -10781,4 +10543,31 @@ do_tablejump (index, mode, range, table_label, default_label)
     emit_barrier ();
 }
 
-#endif /* HAVE_tablejump  */
+int
+try_tablejump (index_type, index_expr, minval, range,
+              table_label, default_label)
+     tree index_type, index_expr, minval, range;
+     rtx table_label, default_label;
+{
+  rtx index;
+
+  if (! HAVE_tablejump)
+    return 0;
+
+  index_expr = fold (build (MINUS_EXPR, index_type,
+                           convert (index_type, index_expr),
+                           convert (index_type, minval)));
+  index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+  emit_queue ();
+  index = protect_from_queue (index, 0);
+  do_pending_stack_adjust ();
+
+  do_tablejump (index, TYPE_MODE (index_type),
+               convert_modes (TYPE_MODE (index_type),
+                              TYPE_MODE (TREE_TYPE (range)),
+                              expand_expr (range, NULL_RTX,
+                                           VOIDmode, 0),
+                              TREE_UNSIGNED (TREE_TYPE (range))),
+               table_label, default_label);
+  return 1;
+}