OSDN Git Service

* stor-layout.c (layout_type): Complain if an array's size can
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index fbe5fe5..e8774e4 100644 (file)
@@ -1,23 +1,23 @@
 /* Convert tree expression to rtl instructions, for GNU compiler.
-   Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
-   Free Software Foundation, Inc.
+   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"
@@ -30,34 +30,20 @@ Boston, MA 02111-1307, USA.  */
 #include "hard-reg-set.h"
 #include "except.h"
 #include "function.h"
-#include "insn-flags.h"
-#include "insn-codes.h"
 #include "insn-config.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"
 #include "typeclass.h"
-#include "defaults.h"
 #include "toplev.h"
 #include "ggc.h"
 #include "intl.h"
 #include "tm_p.h"
 
-#ifndef ACCUMULATE_OUTGOING_ARGS
-#define ACCUMULATE_OUTGOING_ARGS 0
-#endif
-
-/* Supply a default definition for PUSH_ARGS.  */
-#ifndef PUSH_ARGS
-#ifdef PUSH_ROUNDING
-#define PUSH_ARGS      !ACCUMULATE_OUTGOING_ARGS
-#else
-#define PUSH_ARGS      0
-#endif
-#endif
-
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
 
@@ -181,7 +167,6 @@ 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 int readonly_fields_p   PARAMS ((tree));
 static rtx expand_expr_unaligned PARAMS ((tree, unsigned int *));
 static rtx expand_increment    PARAMS ((tree, int, int));
 static void do_jump_by_parts_greater PARAMS ((tree, int, rtx, rtx));
@@ -189,6 +174,10 @@ 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
@@ -213,7 +202,7 @@ static char direct_store[NUM_MACHINE_MODES];
    to perform a structure copy.  */
 #ifndef MOVE_BY_PIECES_P
 #define MOVE_BY_PIECES_P(SIZE, ALIGN) \
-  (move_by_pieces_ninsns (SIZE, ALIGN) < MOVE_RATIO)
+  (move_by_pieces_ninsns (SIZE, ALIGN) < (unsigned int) MOVE_RATIO)
 #endif
 
 /* This array records the insn_code of insns to perform block moves.  */
@@ -400,20 +389,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;
            }
-         return new;
+
+         /* Copy the address into a pseudo, so that the returned value
+            remains correct across calls to emit_queue.  */
+         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)
@@ -438,9 +430,11 @@ protect_from_queue (x, modify)
        }
       return x;
     }
-  /* If the increment has not happened, use the variable itself.  */
+  /* If the increment has not happened, use the variable itself.  Copy it
+     into a new pseudo so that the value remains correct across calls to
+     emit_queue.  */
   if (QUEUED_INSN (x) == 0)
-    return QUEUED_VAR (x);
+    return copy_to_reg (QUEUED_VAR (x));
   /* If the increment has happened and a pre-increment copy exists,
      use that copy.  */
   if (QUEUED_COPY (x) != 0)
@@ -1376,7 +1370,7 @@ convert_modes (mode, oldmode, x, unsignedp)
              && (val & ((HOST_WIDE_INT) 1 << (width - 1))))
            val |= (HOST_WIDE_INT) (-1) << width;
 
-         return GEN_INT (val);
+         return GEN_INT (trunc_int_for_mode (val, mode));
        }
 
       return gen_lowpart (mode, x);
@@ -1398,10 +1392,13 @@ 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.
+
+   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.  */
 
 void
@@ -1411,19 +1408,36 @@ move_by_pieces (to, from, len, align)
      unsigned int align;
 {
   struct move_by_pieces data;
-  rtx to_addr = XEXP (to, 0), from_addr = XEXP (from, 0);
+  rtx to_addr, from_addr = XEXP (from, 0);
   unsigned int max_size = MOVE_MAX_PIECES + 1;
   enum machine_mode mode = VOIDmode, tmode;
   enum insn_code icode;
 
   data.offset = 0;
-  data.to_addr = to_addr;
   data.from_addr = from_addr;
-  data.to = to;
+  if (to)
+    {
+      to_addr = XEXP (to, 0);
+      data.to = to;
+      data.autinc_to
+       = (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC
+          || GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC);
+      data.reverse
+       = (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
+    }
+  else
+    {
+      to_addr = NULL_RTX;
+      data.to = NULL_RTX;
+      data.autinc_to = 1;
+#ifdef STACK_GROWS_DOWNWARD
+      data.reverse = 1;
+#else
+      data.reverse = 0;
+#endif
+    }
+  data.to_addr = to_addr;
   data.from = from;
-  data.autinc_to
-    = (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC
-       || GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC);
   data.autinc_from
     = (GET_CODE (from_addr) == PRE_INC || GET_CODE (from_addr) == PRE_DEC
        || GET_CODE (from_addr) == POST_INC
@@ -1431,8 +1445,6 @@ move_by_pieces (to, from, len, align)
 
   data.explicit_inc_from = 0;
   data.explicit_inc_to = 0;
-  data.reverse
-    = (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
   if (data.reverse) data.offset = len;
   data.len = len;
 
@@ -1508,7 +1520,7 @@ move_by_pieces (to, from, len, align)
 }
 
 /* Return number of insns required to move L bytes by pieces.
-   ALIGN (in bytes) is maximum alignment we can assume.  */
+   ALIGN (in bits) is maximum alignment we can assume.  */
 
 static unsigned HOST_WIDE_INT
 move_by_pieces_ninsns (l, align)
@@ -1558,37 +1570,47 @@ 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)
     {
       if (data->reverse)
        data->offset -= size;
 
-      if (data->autinc_to)
+      if (data->to)
        {
-         to1 = gen_rtx_MEM (mode, data->to_addr);
-         MEM_COPY_ATTRIBUTES (to1, data->to);
+         if (data->autinc_to)
+           {
+             to1 = replace_equiv_address (data->to, data->to_addr);
+             to1 = adjust_address (to1, mode, 0);
+           }
+         else
+           to1 = adjust_address (data->to, mode, data->offset);
        }
-      else
-       to1 = change_address (data->to, mode,
-                             plus_constant (data->to_addr, data->offset));
 
       if (data->autinc_from)
        {
-         from1 = gen_rtx_MEM (mode, data->from_addr);
-         MEM_COPY_ATTRIBUTES (from1, data->from);
+         from1 = replace_equiv_address (data->from, data->from_addr);
+         from1 = adjust_address (from1, mode, 0);
        }
       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)));
       if (HAVE_PRE_DECREMENT && data->explicit_inc_from < 0)
        emit_insn (gen_add2_insn (data->from_addr, GEN_INT (-size)));
 
-      emit_insn ((*genfun) (to1, from1));
+      if (data->to)
+       emit_insn ((*genfun) (to1, from1));
+      else
+       {
+#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)));
@@ -1759,7 +1781,8 @@ emit_block_move (x, y, size, align)
          DECL_EXTERNAL (fn) = 1;
          TREE_PUBLIC (fn) = 1;
          DECL_ARTIFICIAL (fn) = 1;
-         make_decl_rtl (fn, NULL_PTR, 1);
+         TREE_NOTHROW (fn) = 1;
+         make_decl_rtl (fn, NULL);
          assemble_external (fn);
        }
 
@@ -1858,13 +1881,15 @@ move_block_from_reg (regno, x, nregs, size)
 #endif
   enum machine_mode mode;
 
+  if (nregs == 0)
+    return;
+
   /* If SIZE is that of a mode no bigger than a word, just use that
      mode's store operation.  */
   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;
     }
 
@@ -1947,18 +1972,6 @@ emit_group_load (dst, orig_src, ssize, align)
 
   tmps = (rtx *) alloca (sizeof (rtx) * XVECLEN (dst, 0));
 
-  /* If we won't be loading directly from memory, protect the real source
-     from strange tricks we might play.  */
-  src = orig_src;
-  if (GET_CODE (src) != MEM && ! CONSTANT_P (src))
-    {
-      if (GET_MODE (src) == VOIDmode)
-       src = gen_reg_rtx (GET_MODE (dst));
-      else
-       src = gen_reg_rtx (GET_MODE (orig_src));
-      emit_move_insn (src, orig_src);
-    }
-
   /* Process the pieces.  */
   for (i = start; i < XVECLEN (dst, 0); i++)
     {
@@ -1968,7 +1981,7 @@ emit_group_load (dst, orig_src, ssize, align)
       int shift = 0;
 
       /* Handle trailing fragments that run over the size of the struct.  */
-      if (ssize >= 0 && bytepos + bytelen > ssize)
+      if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
        {
          shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
          bytelen = ssize - bytepos;
@@ -1976,6 +1989,22 @@ emit_group_load (dst, orig_src, ssize, align)
            abort ();
        }
 
+      /* If we won't be loading directly from memory, protect the real source
+        from strange tricks we might play; but make sure that the source can
+        be loaded directly into the destination.  */
+      src = orig_src;
+      if (GET_CODE (orig_src) != MEM
+         && (!CONSTANT_P (orig_src)
+             || (GET_MODE (orig_src) != mode
+                 && GET_MODE (orig_src) != VOIDmode)))
+       {
+         if (GET_MODE (orig_src) == VOIDmode)
+           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)
@@ -1983,24 +2012,20 @@ emit_group_load (dst, orig_src, ssize, align)
          && 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)
        {
          if (bytepos == 0
              && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 0))))
            tmps[i] = XEXP (src, 0);
-         else if (bytepos == GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
+         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
            abort ();
        }
-      else if ((CONSTANT_P (src)
-               && (GET_MODE (src) == VOIDmode || GET_MODE (src) == mode))
+      else if (CONSTANT_P (src)
               || (GET_CODE (src) == REG && GET_MODE (src) == mode))
        tmps[i] = src;
       else
@@ -2091,7 +2116,7 @@ emit_group_store (orig_dst, src, ssize, align)
       unsigned int bytelen = GET_MODE_SIZE (mode);
 
       /* Handle trailing fragments that run over the size of the struct.  */
-      if (ssize >= 0 && bytepos + bytelen > ssize)
+      if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
        {
          if (BYTES_BIG_ENDIAN)
            {
@@ -2107,13 +2132,10 @@ emit_group_store (orig_dst, src, ssize, align)
          && align >= 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], align, ssize);
     }
 
   emit_queue ();
@@ -2145,8 +2167,10 @@ copy_blkmode_from_reg (tgtblk, srcreg, type)
 
   if (tgtblk == 0)
     {
-      tgtblk = assign_stack_temp (BLKmode, bytes, 0);
-      MEM_SET_IN_STRUCT_P (tgtblk, AGGREGATE_TYPE_P (type));
+      tgtblk = assign_temp (build_qualified_type (type,
+                                                 (TYPE_QUALS (type)
+                                                  | TYPE_QUAL_CONST)),
+                           0, 1, 1);
       preserve_temp_slots (tgtblk);
     }
 
@@ -2178,7 +2202,8 @@ copy_blkmode_from_reg (tgtblk, srcreg, type)
         (the first time through).  */
       if (xbitpos % BITS_PER_WORD == 0
          || xbitpos == big_endian_correction)
-       src = operand_subword_force (srcreg, xbitpos / BITS_PER_WORD, BLKmode);
+       src = operand_subword_force (srcreg, xbitpos / BITS_PER_WORD,
+                                    GET_MODE (srcreg));
 
       /* We need a new destination operand each time bitpos is on
         a word boundary.  */
@@ -2368,7 +2393,7 @@ clear_by_pieces (to, len, align)
   struct store_by_pieces data;
 
   data.constfun = clear_by_pieces_1;
-  data.constfundata = NULL_PTR;
+  data.constfundata = NULL;
   data.len = len;
   data.to = to;
   store_by_pieces_1 (&data, align);
@@ -2493,12 +2518,11 @@ store_by_pieces_2 (genfun, mode, data)
 
       if (data->autinc_to)
        {
-         to1 = gen_rtx_MEM (mode, data->to_addr);
-         MEM_COPY_ATTRIBUTES (to1, data->to);
+         to1 = replace_equiv_address (data->to, data->to_addr);
+         to1 = adjust_address (to1, mode, 0);
        }
       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,
@@ -2538,7 +2562,7 @@ clear_storage (object, size, align)
      just move a zero.  Otherwise, do this a piece at a time.  */
   if (GET_MODE (object) != BLKmode
       && GET_CODE (size) == CONST_INT
-      && GET_MODE_SIZE (GET_MODE (object)) == INTVAL (size))
+      && GET_MODE_SIZE (GET_MODE (object)) == (unsigned int) INTVAL (size))
     emit_move_insn (object, CONST0_RTX (GET_MODE (object)));
   else
     {
@@ -2636,7 +2660,7 @@ clear_storage (object, size, align)
 
             For targets where libcalls and normal calls have different
             conventions for returning pointers, we could end up generating
-             incorrect code.
+            incorrect code.
 
             So instead of using a libcall sequence we build up a suitable
             CALL_EXPR and expand the call in the normal fashion.  */
@@ -2654,7 +2678,8 @@ clear_storage (object, size, align)
              DECL_EXTERNAL (fn) = 1;
              TREE_PUBLIC (fn) = 1;
              DECL_ARTIFICIAL (fn) = 1;
-             make_decl_rtl (fn, NULL_PTR, 1);
+             TREE_NOTHROW (fn) = 1;
+             make_decl_rtl (fn, NULL);
              assemble_external (fn);
            }
 
@@ -2705,6 +2730,8 @@ emit_move_insn (x, y)
      rtx x, y;
 {
   enum machine_mode mode = GET_MODE (x);
+  rtx y_cst = NULL_RTX;
+  rtx last_insn;
 
   x = protect_from_queue (x, 1);
   y = protect_from_queue (y, 0);
@@ -2716,7 +2743,10 @@ emit_move_insn (x, y)
   if (GET_CODE (y) == CONSTANT_P_RTX)
     ;
   else if (CONSTANT_P (y) && ! LEGITIMATE_CONSTANT_P (y))
-    y = force_const_mem (mode, y);
+    {
+      y_cst = y;
+      y = force_const_mem (mode, y);
+    }
 
   /* If X or Y are memory references, verify that their addresses are valid
      for the machine.  */
@@ -2725,18 +2755,24 @@ 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 ();
 
-  return emit_move_insn_1 (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));
+
+  return last_insn;
 }
 
 /* Low level part of emit_move_insn.
@@ -2752,7 +2788,7 @@ emit_move_insn_1 (x, y)
   enum mode_class class = GET_MODE_CLASS (mode);
   unsigned int i;
 
-  if (mode >= MAX_MACHINE_MODE)
+  if ((unsigned int) mode >= (unsigned int) MAX_MACHINE_MODE)
     abort ();
 
   if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
@@ -2772,6 +2808,52 @@ emit_move_insn_1 (x, y)
       /* Don't split destination if it is a stack push.  */
       int stack = push_operand (x, GET_MODE (x));
 
+#ifdef PUSH_ROUNDING
+      /* In case we output to the stack, but the size is smaller machine can
+        push exactly, we need to use move instructions.  */
+      if (stack
+         && PUSH_ROUNDING (GET_MODE_SIZE (submode)) != GET_MODE_SIZE (submode))
+       {
+         rtx temp;
+         int offset1, offset2;
+
+         /* 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);
+#ifdef STACK_GROWS_DOWNWARD
+         offset1 = 0;
+         offset2 = GET_MODE_SIZE (submode);
+#else
+         offset1 = -PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)));
+         offset2 = (-PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)))
+                    + GET_MODE_SIZE (submode));
+#endif
+         emit_move_insn (change_address (x, submode,
+                                         gen_rtx_PLUS (Pmode,
+                                                       stack_pointer_rtx,
+                                                       GEN_INT (offset1))),
+                         gen_realpart (submode, y));
+         emit_move_insn (change_address (x, submode,
+                                         gen_rtx_PLUS (Pmode,
+                                                       stack_pointer_rtx,
+                                                       GEN_INT (offset2))),
+                         gen_imagpart (submode, y));
+       }
+      else
+#endif
       /* If this is a stack, push the highpart first, so it
         will be in the argument order.
 
@@ -2822,17 +2904,17 @@ emit_move_insn_1 (x, y)
                  enum mode_class reg_class = ((class == MODE_COMPLEX_FLOAT)
                                               ? MODE_FLOAT : MODE_INT);
 
-                 enum machine_mode reg_mode =
-                   mode_for_size (GET_MODE_BITSIZE (mode), reg_class, 1);
+                 enum machine_mode reg_mode
+                   mode_for_size (GET_MODE_BITSIZE (mode), reg_class, 1);
 
                  if (reg_mode != BLKmode)
                    {
                      rtx mem = assign_stack_temp (reg_mode,
                                                   GET_MODE_SIZE (mode), 0);
+                     rtx cmem = adjust_address (mem, mode, 0);
 
-                     rtx cmem = change_address (mem, mode, NULL_RTX);
-
-                     cfun->cannot_inline = N_("function using short complex types cannot be inline");
+                     cfun->cannot_inline
+                       = N_("function using short complex types cannot be inline");
 
                      if (packed_dest_p)
                        {
@@ -2891,8 +2973,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
 
@@ -2900,20 +3013,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 ();
 
@@ -2999,18 +3102,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);
@@ -3031,11 +3127,6 @@ push_block (size, extra, below)
   return memory_address (GET_CLASS_NARROWEST_MODE (MODE_INT), temp);
 }
 
-rtx
-gen_push_operand ()
-{
-  return gen_rtx_fmt_e (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);
-}
 
 /* Return an rtx for the address of the beginning of a as-if-it-was-pushed
    block of SIZE bytes.  */
@@ -3056,6 +3147,63 @@ 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;
+{
+  rtx dest_addr;
+  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 (-(HOST_WIDE_INT)rounded_size));
+#else
+      dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+                               GEN_INT (rounded_size));
+#endif
+      dest_addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx, dest_addr);
+    }
+
+  dest = gen_rtx_MEM (mode, dest_addr);
+
+  if (type != 0)
+    {
+      set_mem_attributes (dest, type, 1);
+      /* Function incoming arguments may overlap with sibling call
+         outgoing arguments and we cannot allow reordering of reads
+         from function arguments with stores to outgoing arguments
+         of sibling calls.  */
+      set_mem_alias_set (dest, 0);
+    }
+  emit_move_insn (dest, x);
+}
+#endif
+
 /* Generate code to push X onto the stack, assuming it has mode MODE and
    type TYPE.
    MODE is redundant except when X is a CONST_INT (since they don't
@@ -3063,7 +3211,7 @@ get_push_address (size)
    SIZE is an rtx for the size of data to be copied (in bytes),
    needed only if X is BLKmode.
 
-   ALIGN is maximum alignment we can assume.
+   ALIGN (in bits) is maximum alignment we can assume.
 
    If PARTIAL and REG are both nonzero, then copy that many of the first
    words of X into registers starting with REG, and push the rest of X.
@@ -3118,8 +3266,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);
 
@@ -3143,8 +3292,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.
@@ -3166,7 +3314,8 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
             and such small pushes do rounding that causes trouble.  */
          && ((! SLOW_UNALIGNED_ACCESS (word_mode, align))
              || align >= BIGGEST_ALIGNMENT
-             || PUSH_ROUNDING (align) == align)
+             || (PUSH_ROUNDING (align / BITS_PER_UNIT)
+                 == (align / BITS_PER_UNIT)))
          && PUSH_ROUNDING (INTVAL (size)) == INTVAL (size))
        {
          /* Push padding now if padding above and stack grows down,
@@ -3176,9 +3325,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
              && where_pad != none && where_pad != stack_direction)
            anti_adjust_stack (GEN_INT (extra));
 
-         stack_pointer_delta += INTVAL (size) - used;
-         move_by_pieces (gen_rtx_MEM (BLKmode, gen_push_operand ()), xinner,
-                         INTVAL (size) - used, align);
+         move_by_pieces (NULL, xinner, INTVAL (size) - used, align);
 
          if (current_function_check_memory_usage && ! in_check_memory_usage)
            {
@@ -3268,7 +3415,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 (target) = 0;
+             set_mem_alias_set (target, 0);
            }
 
          /* TEMP is the address of the block.  Copy the data there.  */
@@ -3430,10 +3577,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
 
 #ifdef PUSH_ROUNDING
       if (args_addr == 0 && PUSH_ARGS)
-       {
-         addr = gen_push_operand ();
-         stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
-       }
+       emit_single_push_insn (mode, x, type);
       else
 #endif
        {
@@ -3446,20 +3590,20 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
            addr = memory_address (mode, gen_rtx_PLUS (Pmode, args_addr,
                                                       args_so_far));
          target = addr;
-       }
+         dest = gen_rtx_MEM (mode, addr);
+         if (type != 0)
+           {
+             set_mem_attributes (dest, type, 1);
+             /* Function incoming arguments may overlap with sibling call
+                outgoing arguments and we cannot allow reordering of reads
+                from function arguments with stores to outgoing arguments
+                of sibling calls.  */
+             set_mem_alias_set (dest, 0);
+           }
 
-      dest = gen_rtx_MEM (mode, addr);
-      if (type != 0)
-       {
-         set_mem_attributes (dest, type, 1);
-         /* Function incoming arguments may overlap with sibling call
-            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;
-       }
+         emit_move_insn (dest, x);
 
-      emit_move_insn (dest, x);
+       }
 
       if (current_function_check_memory_usage && ! in_check_memory_usage)
        {
@@ -3560,7 +3704,7 @@ expand_assignment (to, from, want_value, suggest_reg)
      problem.  */
 
   if (TREE_CODE (to) == COMPONENT_REF || TREE_CODE (to) == BIT_FIELD_REF
-      || TREE_CODE (to) == ARRAY_REF)
+      || TREE_CODE (to) == ARRAY_REF || TREE_CODE (to) == ARRAY_RANGE_REF)
     {
       enum machine_mode mode1;
       HOST_WIDE_INT bitsize, bitpos;
@@ -3607,16 +3751,15 @@ expand_assignment (to, from, want_value, suggest_reg)
              && (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
              && alignment == 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;
            }
 
@@ -3692,9 +3835,7 @@ expand_assignment (to, from, want_value, suggest_reg)
          unsigned int from_align;
          rtx from_rtx = expand_expr_unaligned (from, &from_align);
          rtx inner_to_rtx
-           = change_address (to_rtx, VOIDmode,
-                             plus_constant (XEXP (to_rtx, 0),
-                                            bitpos / BITS_PER_UNIT));
+           = adjust_address (to_rtx, BLKmode, bitpos / BITS_PER_UNIT);
 
          emit_block_move (inner_to_rtx, from_rtx, expr_size (from),
                           MIN (alignment, from_align));
@@ -3781,7 +3922,7 @@ expand_assignment (to, from, want_value, suggest_reg)
     {
       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);
+       set_mem_alias_set (to_rtx, get_alias_set (to));
     }
 
   /* Don't move directly into a return register.  */
@@ -3829,7 +3970,7 @@ expand_assignment (to, from, want_value, suggest_reg)
                           TYPE_MODE (sizetype));
 
 #ifdef TARGET_MEM_FUNCTIONS
-      emit_library_call (memcpy_libfunc, LCT_NORMAL,
+      emit_library_call (memmove_libfunc, LCT_NORMAL,
                         VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
                         XEXP (from_rtx, 0), Pmode,
                         convert_to_mode (TYPE_MODE (sizetype),
@@ -3891,6 +4032,7 @@ store_expr (exp, target, want_value)
 {
   register rtx temp;
   int dont_return_target = 0;
+  int dont_store_target = 0;
 
   if (TREE_CODE (exp) == COMPOUND_EXPR)
     {
@@ -3961,7 +4103,15 @@ store_expr (exp, target, want_value)
     {
       temp = expand_expr (exp, target, GET_MODE (target), 0);
       if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)
-       temp = copy_to_reg (temp);
+       {
+         /* If TEMP is already in the desired TARGET, only copy it from
+            memory and don't store it there again.  */
+         if (temp == target
+             || (rtx_equal_p (temp, target)
+                 && ! side_effects_p (temp) && ! side_effects_p (target)))
+           dont_store_target = 1;
+         temp = copy_to_reg (temp);
+       }
       dont_return_target = 1;
     }
   else if (GET_CODE (target) == SUBREG && SUBREG_PROMOTED_VAR_P (target))
@@ -4019,7 +4169,7 @@ store_expr (exp, target, want_value)
       if (want_value && GET_MODE (temp) != GET_MODE (target)
          && GET_MODE (temp) != VOIDmode)
        {
-         temp = gen_rtx_SUBREG (GET_MODE (target), temp, 0);
+         temp = gen_lowpart_SUBREG (GET_MODE (target), temp);
          SUBREG_PROMOTED_VAR_P (temp) = 1;
          SUBREG_PROMOTED_UNSIGNED_P (temp)
            = SUBREG_PROMOTED_UNSIGNED_P (target);
@@ -4091,7 +4241,8 @@ store_expr (exp, target, want_value)
   if ((! rtx_equal_p (temp, target)
        || (temp != target && (side_effects_p (temp)
                              || side_effects_p (target))))
-      && TREE_CODE (exp) != ERROR_MARK)
+      && TREE_CODE (exp) != ERROR_MARK
+      && ! dont_store_target)
     {
       target = protect_from_queue (target, 1);
       if (GET_MODE (temp) != GET_MODE (target)
@@ -4150,9 +4301,10 @@ 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, (BITS_PER_UNIT
-                                      * (INTVAL (copy_size_rtx)
-                                         & - INTVAL (copy_size_rtx))));
+                 align = MIN (align,
+                              (unsigned int) (BITS_PER_UNIT
+                                              * (INTVAL (copy_size_rtx)
+                                                 & - INTVAL (copy_size_rtx))));
                }
              else
                {
@@ -4330,16 +4482,20 @@ store_constructor_field (target, bitsize, bitpos,
     {
       if (bitpos != 0)
        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;
+       set_mem_alias_set (target, alias_set);
+
       store_constructor (exp, target, align, cleared, bitsize / BITS_PER_UNIT);
     }
   else
@@ -4414,7 +4570,7 @@ store_constructor (exp, target, align, cleared, size)
 
       /* If the constructor has fewer fields than the structure
         or if we are initializing the structure to mostly zeros,
-        clear the whole structure first.  Don't do this is TARGET is
+        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
@@ -4422,7 +4578,7 @@ store_constructor (exp, target, align, cleared, size)
                    != fields_length (type))
                   || mostly_zeros_p (exp))
               && (GET_CODE (target) != REG
-                  || 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);
@@ -4559,8 +4715,8 @@ store_constructor (exp, target, align, cleared, size)
       tree elttype = TREE_TYPE (type);
       int const_bounds_p = (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)
@@ -4625,7 +4781,7 @@ store_constructor (exp, target, align, cleared, size)
            clear_storage (target, GEN_INT (size), align);
          cleared = 1;
        }
-      else
+      else if (REG_P (target))
        /* Inform later passes that the old value is dead.  */
        emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
 
@@ -4700,10 +4856,10 @@ store_constructor (exp, target, align, cleared, size)
 
                  index = build_decl (VAR_DECL, NULL_TREE, domain);
 
-                 DECL_RTL (index) = index_r
+                 index_r
                    = gen_reg_rtx (promote_mode (domain, DECL_MODE (index),
                                                 &unsignedp, 0));
-
+                 SET_DECL_RTL (index, index_r);
                  if (TREE_CODE (value) == SAVE_EXPR
                      && SAVE_EXPR_RTL (value) == 0)
                    {
@@ -4777,6 +4933,7 @@ store_constructor (exp, target, align, cleared, size)
              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));
 
@@ -4855,10 +5012,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
@@ -4921,9 +5075,11 @@ store_constructor (exp, target, align, cleared, size)
 
          if (REG_P (target))
            {
-             targetx = assign_stack_temp (GET_MODE (target),
-                                          GET_MODE_SIZE (GET_MODE (target)),
-                                          0);
+             targetx
+               = assign_temp
+                 ((build_qualified_type (type_for_mode (GET_MODE (target), 0),
+                                         TYPE_QUAL_CONST)),
+                  0, 1, 1);
              emit_move_insn (targetx, target);
            }
 
@@ -5005,6 +5161,11 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
   if (TREE_CODE (exp) == ERROR_MARK)
     return const0_rtx;
 
+  /* If we have nothing to store, do nothing unless the expression has
+     side-effects.  */
+  if (bitsize == 0)
+    return expand_expr (exp, const0_rtx, VOIDmode, 0);
+
   if (bitsize < HOST_BITS_PER_WIDE_INT)
     width_mask = ((HOST_WIDE_INT) 1 << bitsize) - 1;
 
@@ -5022,15 +5183,16 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
   if (mode == BLKmode
       && (GET_CODE (target) == REG || GET_CODE (target) == SUBREG))
     {
-      rtx object = assign_stack_temp (GET_MODE (target),
-                                     GET_MODE_SIZE (GET_MODE (target)), 0);
+      rtx object
+       = assign_temp
+         (build_qualified_type (type_for_mode (GET_MODE (target), 0),
+                                TYPE_QUAL_CONST),
+          0, 1, 1);
       rtx blk_object = copy_rtx (object);
 
-      MEM_SET_IN_STRUCT_P (object, 1);
-      MEM_SET_IN_STRUCT_P (blk_object, 1);
       PUT_MODE (blk_object, BLKmode);
 
-      if (bitsize != GET_MODE_BITSIZE (GET_MODE (target)))
+      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,
@@ -5108,9 +5270,7 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
              || bitpos % BITS_PER_UNIT != 0)
            abort ();
 
-         target = change_address (target, VOIDmode,
-                                  plus_constant (XEXP (target, 0),
-                                               bitpos / BITS_PER_UNIT));
+         target = adjust_address (target, VOIDmode, bitpos / BITS_PER_UNIT);
 
          /* Make sure that ALIGN is no stricter than the alignment of EXP.  */
          align = MIN (exp_align, align);
@@ -5141,7 +5301,13 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
              enum machine_mode tmode;
 
              if (unsignedp)
-               return expand_and (temp, GEN_INT (width_mask), NULL_RTX);
+               return expand_and (temp,
+                                  GEN_INT
+                                  (trunc_int_for_mode
+                                   (width_mask,
+                                    GET_MODE (temp) == VOIDmode
+                                    ? value_mode
+                                    : GET_MODE (temp))), NULL_RTX);
              tmode = GET_MODE (temp);
              if (tmode == VOIDmode)
                tmode = value_mode;
@@ -5170,24 +5336,31 @@ 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);
+       target = replace_equiv_address (target, 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 = copy_rtx (adjust_address (target, mode,
+                                        bitpos / BITS_PER_UNIT));
+
       MEM_SET_IN_STRUCT_P (to_rtx, 1);
-      MEM_ALIAS_SET (to_rtx) = alias_set;
+      /* 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.  */
+      set_mem_alias_set (to_rtx,
+                        rtx_varies_p (addr, /*for_alias=*/0)
+                        ? 0 : alias_set);
 
       return store_expr (exp, to_rtx, value_mode != VOIDmode);
     }
 }
 \f
 /* Given an expression EXP that may be a COMPONENT_REF, a BIT_FIELD_REF,
-   or an ARRAY_REF, look for nested COMPONENT_REFs, BIT_FIELD_REFs, or
-   ARRAY_REFs and find the ultimate containing object, which we return.
+   an ARRAY_REF, or an ARRAY_RANGE_REF, look for nested operations of these
+   codes and find the ultimate containing object, which we return.
 
    We set *PBITSIZE to the size in bits that we want, *PBITPOS to the
    bit position, and *PUNSIGNEDP to the signedness of the field.
@@ -5291,12 +5464,14 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
            alignment = MIN (alignment, DECL_OFFSET_ALIGN (field));
        }
 
-      else if (TREE_CODE (exp) == ARRAY_REF)
+      else if (TREE_CODE (exp) == ARRAY_REF
+              || TREE_CODE (exp) == ARRAY_RANGE_REF)
        {
          tree index = TREE_OPERAND (exp, 1);
-         tree domain = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0)));
+         tree array = TREE_OPERAND (exp, 0);
+         tree domain = TYPE_DOMAIN (TREE_TYPE (array));
          tree low_bound = (domain ? TYPE_MIN_VALUE (domain) : 0);
-         tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (exp));
+         tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array)));
 
          /* We assume all arrays have sizes that are a multiple of a byte.
             First subtract the lower bound, if any, in the type of the
@@ -5314,8 +5489,7 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
            index = build (WITH_RECORD_EXPR, TREE_TYPE (index), index, exp);
          if (! TREE_CONSTANT (unit_size)
              && contains_placeholder_p (unit_size))
-           unit_size = build (WITH_RECORD_EXPR, sizetype, unit_size,
-                              TREE_OPERAND (exp, 0));
+           unit_size = build (WITH_RECORD_EXPR, sizetype, unit_size, array);
 
          offset = size_binop (PLUS_EXPR, offset,
                               size_binop (MULT_EXPR,
@@ -5394,10 +5568,10 @@ get_memory_usage_from_modifier (modifier)
     }
 }
 \f
-/* Given an rtx VALUE that may contain additions and multiplications,
-   return an equivalent value that just refers to a register or memory.
-   This is done by generating instructions to perform the arithmetic
-   and returning a pseudo-register containing the value.
+/* Given an rtx VALUE that may contain additions and multiplications, return
+   an equivalent value that just refers to a register, memory, or constant.
+   This is done by generating instructions to perform the arithmetic and
+   returning a pseudo-register containing the value.
 
    The returned value may be a REG, SUBREG, MEM or constant.  */
 
@@ -5506,14 +5680,18 @@ save_noncopied_parts (lhs, list)
        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 (part_type, 0, 1, 1);
-       if (! memory_address_p (TYPE_MODE (part_type), XEXP (target, 0)))
-         target = change_address (target, TYPE_MODE (part_type), NULL_RTX);
+       rtx target
+         = assign_temp (build_qualified_type (part_type,
+                                              (TYPE_QUALS (part_type)
+                                               | TYPE_QUAL_CONST)),
+                        0, 1, 1);
+
        parts = tree_cons (to_be_saved,
                           build (RTL_EXPR, part_type, NULL_TREE,
-                                 (tree) target),
+                                 (tree) validize_mem (target)),
                           parts);
-       store_expr (TREE_PURPOSE (parts), RTL_EXPR_RTL (TREE_VALUE (parts)), 0);
+       store_expr (TREE_PURPOSE (parts),
+                   RTL_EXPR_RTL (TREE_VALUE (parts)), 0);
       }
   return parts;
 }
@@ -5559,10 +5737,7 @@ safe_from_p (x, exp, top_p)
 {
   rtx exp_rtl = 0;
   int i, nops;
-  static int save_expr_count;
-  static int save_expr_size = 0;
-  static tree *save_expr_rewritten;
-  static tree save_expr_trees[256];
+  static tree save_expr_list;
 
   if (x == 0
       /* If EXP has varying size, we MUST use a target since we currently
@@ -5577,31 +5752,14 @@ safe_from_p (x, exp, top_p)
              || TYPE_ARRAY_MAX_SIZE (TREE_TYPE (exp)) == NULL_TREE
              || TREE_CODE (TYPE_ARRAY_MAX_SIZE (TREE_TYPE (exp)))
              != INTEGER_CST)
-         && GET_MODE (x) == BLKmode))
+         && GET_MODE (x) == BLKmode)
+      /* If X is in the outgoing argument area, it is always safe.  */
+      || (GET_CODE (x) == MEM
+         && (XEXP (x, 0) == virtual_outgoing_args_rtx
+             || (GET_CODE (XEXP (x, 0)) == PLUS
+                 && XEXP (XEXP (x, 0), 0) == virtual_outgoing_args_rtx))))
     return 1;
 
-  if (top_p && save_expr_size == 0)
-    {
-      int rtn;
-
-      save_expr_count = 0;
-      save_expr_size = ARRAY_SIZE (save_expr_trees);
-      save_expr_rewritten = &save_expr_trees[0];
-
-      rtn = safe_from_p (x, exp, 1);
-
-      for (i = 0; i < save_expr_count; ++i)
-       {
-         if (TREE_CODE (save_expr_trees[i]) != ERROR_MARK)
-           abort ();
-         TREE_SET_CODE (save_expr_trees[i], SAVE_EXPR);
-       }
-
-      save_expr_size = 0;
-
-      return rtn;
-    }
-
   /* If this is a subreg of a hard register, declare it unsafe, otherwise,
      find the underlying pseudo.  */
   if (GET_CODE (x) == SUBREG)
@@ -5611,17 +5769,35 @@ safe_from_p (x, exp, top_p)
        return 0;
     }
 
-  /* If X is a location in the outgoing argument area, it is always safe.  */
-  if (GET_CODE (x) == MEM
-      && (XEXP (x, 0) == virtual_outgoing_args_rtx
-         || (GET_CODE (XEXP (x, 0)) == PLUS
-             && XEXP (XEXP (x, 0), 0) == virtual_outgoing_args_rtx)))
-    return 1;
+  /* A SAVE_EXPR might appear many times in the expression passed to the
+     top-level safe_from_p call, and if it has a complex subexpression,
+     examining it multiple times could result in a combinatorial explosion.
+     E.g. on an Alpha running at least 200MHz, a Fortran test case compiled
+     with optimization took about 28 minutes to compile -- even though it was
+     only a few lines long.  So we mark each SAVE_EXPR we see with TREE_PRIVATE
+     and turn that off when we are done.  We keep a list of the SAVE_EXPRs
+     we have processed.  Note that the only test of top_p was above.  */
+
+  if (top_p)
+    {
+      int rtn;
+      tree t;
+
+      save_expr_list = 0;
+
+      rtn = safe_from_p (x, exp, 0);
 
+      for (t = save_expr_list; t != 0; t = TREE_CHAIN (t))
+       TREE_PRIVATE (TREE_PURPOSE (t)) = 0;
+
+      return rtn;
+    }
+
+  /* Now look at our tree code and possibly recurse.  */
   switch (TREE_CODE_CLASS (TREE_CODE (exp)))
     {
     case 'd':
-      exp_rtl = DECL_RTL (exp);
+      exp_rtl = DECL_RTL_SET_P (exp) ? DECL_RTL (exp) : NULL_RTX;
       break;
 
     case 'c':
@@ -5657,11 +5833,13 @@ safe_from_p (x, exp, top_p)
        {
        case ADDR_EXPR:
          return (staticp (TREE_OPERAND (exp, 0))
-                 || safe_from_p (x, TREE_OPERAND (exp, 0), 0)
-                 || TREE_STATIC (exp));
+                 || TREE_STATIC (exp)
+                 || safe_from_p (x, TREE_OPERAND (exp, 0), 0));
 
        case INDIRECT_REF:
-         if (GET_CODE (x) == MEM)
+         if (GET_CODE (x) == MEM
+             && alias_sets_conflict_p (MEM_ALIAS_SET (x),
+                                       get_alias_set (exp)))
            return 0;
          break;
 
@@ -5684,7 +5862,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:
@@ -5695,37 +5873,20 @@ safe_from_p (x, exp, top_p)
          if (exp_rtl)
            break;
 
-         /* This SAVE_EXPR might appear many times in the top-level
-            safe_from_p() expression, and if it has a complex
-            subexpression, examining it multiple times could result
-            in a combinatorial explosion.  E.g. on an Alpha
-            running at least 200MHz, a Fortran test case compiled with
-            optimization took about 28 minutes to compile -- even though
-            it was only a few lines long, and the complicated line causing
-            so much time to be spent in the earlier version of safe_from_p()
-            had only 293 or so unique nodes.
-
-            So, turn this SAVE_EXPR into an ERROR_MARK for now, but remember
-            where it is so we can turn it back in the top-level safe_from_p()
-            when we're done.  */
-
-         /* For now, don't bother re-sizing the array.  */
-         if (save_expr_count >= save_expr_size)
-           return 0;
-         save_expr_rewritten[save_expr_count++] = exp;
+         /* If we've already scanned this, don't do it again.  Otherwise,
+            show we've scanned it and record for clearing the flag if we're
+            going on.  */
+         if (TREE_PRIVATE (exp))
+           return 1;
 
-         nops = TREE_CODE_LENGTH (SAVE_EXPR);
-         for (i = 0; i < nops; i++)
+         TREE_PRIVATE (exp) = 1;
+         if (! safe_from_p (x, TREE_OPERAND (exp, 0), 0))
            {
-             tree operand = TREE_OPERAND (exp, i);
-             if (operand == NULL_TREE)
-               continue;
-             TREE_SET_CODE (exp, ERROR_MARK);
-             if (!safe_from_p (x, operand, 0))
-               return 0;
-             TREE_SET_CODE (exp, SAVE_EXPR);
+             TREE_PRIVATE (exp) = 0;
+             return 0;
            }
-         TREE_SET_CODE (exp, ERROR_MARK);
+
+         save_expr_list = tree_cons (exp, NULL_TREE, save_expr_list);
          return 1;
 
        case BIND_EXPR:
@@ -5753,7 +5914,8 @@ safe_from_p (x, exp, top_p)
 
       /* If this is a language-specific tree code, it may require
         special handling.  */
-      if (TREE_CODE (exp) >= LAST_AND_UNUSED_TREE_CODE
+      if ((unsigned int) TREE_CODE (exp)
+         >= (unsigned int) LAST_AND_UNUSED_TREE_CODE
          && lang_safe_from_p
          && !(*lang_safe_from_p) (x, exp))
        return 0;
@@ -5772,10 +5934,11 @@ safe_from_p (x, exp, top_p)
        }
 
       /* If the rtl is X, then it is not safe.  Otherwise, it is unless both
-        are memory and EXP is not readonly.  */
+        are memory and they conflict.  */
       return ! (rtx_equal_p (x, exp_rtl)
                || (GET_CODE (x) == MEM && GET_CODE (exp_rtl) == MEM
-                   && ! TREE_READONLY (exp)));
+                   && true_dependence (exp_rtl, GET_MODE (x), x,
+                                       rtx_addr_varies_p)));
     }
 
   /* If we reach here, it is safe.  */
@@ -5817,6 +5980,7 @@ var_rtx (exp)
 }
 
 #ifdef MAX_INTEGER_COMPUTATION_MODE
+
 void
 check_max_integer_computation_mode (exp)
      tree exp;
@@ -5842,7 +6006,7 @@ check_max_integer_computation_mode (exp)
       mode = TYPE_MODE (TREE_TYPE (exp));
       if (GET_MODE_CLASS (mode) == MODE_INT
          && mode > MAX_INTEGER_COMPUTATION_MODE)
-       fatal ("unsupported wide integer operation");
+       internal_error ("unsupported wide integer operation");
     }
 
   /* Check operand of a unary op.  */
@@ -5851,7 +6015,7 @@ check_max_integer_computation_mode (exp)
       mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
       if (GET_MODE_CLASS (mode) == MODE_INT
          && mode > MAX_INTEGER_COMPUTATION_MODE)
-       fatal ("unsupported wide integer operation");
+       internal_error ("unsupported wide integer operation");
     }
 
   /* Check operands of a binary/comparison op.  */
@@ -5860,36 +6024,16 @@ check_max_integer_computation_mode (exp)
       mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
       if (GET_MODE_CLASS (mode) == MODE_INT
          && mode > MAX_INTEGER_COMPUTATION_MODE)
-       fatal ("unsupported wide integer operation");
+       internal_error ("unsupported wide integer operation");
 
       mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1)));
       if (GET_MODE_CLASS (mode) == MODE_INT
          && mode > MAX_INTEGER_COMPUTATION_MODE)
-       fatal ("unsupported wide integer operation");
+       internal_error ("unsupported wide integer operation");
     }
 }
 #endif
 \f
-/* Utility function used by expand_expr to see if TYPE, a RECORD_TYPE,
-   has any readonly fields.  If any of the fields have types that
-   contain readonly fields, return true as well.  */
-
-static int
-readonly_fields_p (type)
-     tree type;
-{
-  tree field;
-
-  for (field = TYPE_FIELDS (type); field != 0; field = TREE_CHAIN (field))
-    if (TREE_CODE (field) == FIELD_DECL
-       && (TREE_READONLY (field)
-           || (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
-               && readonly_fields_p (TREE_TYPE (field)))))
-      return 1;
-
-  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.
@@ -5999,10 +6143,12 @@ expand_expr (exp, target, tmode, modifier)
        return expand_expr (TREE_OPERAND (exp, 0), const0_rtx,
                            VOIDmode, ro_modifier);
       else if (TREE_CODE_CLASS (code) == '2' || TREE_CODE_CLASS (code) == '<'
-              || code == ARRAY_REF)
+              || code == ARRAY_REF || code == ARRAY_RANGE_REF)
        {
-         expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, ro_modifier);
-         expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, ro_modifier);
+         expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
+                      ro_modifier);
+         expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode,
+                      ro_modifier);
          return const0_rtx;
        }
       else if ((code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
@@ -6013,9 +6159,12 @@ expand_expr (exp, target, tmode, modifier)
                            VOIDmode, ro_modifier);
       else if (code == BIT_FIELD_REF)
        {
-         expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, ro_modifier);
-         expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, ro_modifier);
-         expand_expr (TREE_OPERAND (exp, 2), const0_rtx, VOIDmode, ro_modifier);
+         expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
+                      ro_modifier);
+         expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode,
+                      ro_modifier);
+         expand_expr (TREE_OPERAND (exp, 2), const0_rtx, VOIDmode,
+                      ro_modifier);
          return const0_rtx;
        }
       ;
@@ -6032,6 +6181,7 @@ expand_expr (exp, target, tmode, modifier)
       && TREE_CODE (exp) != INTEGER_CST
       && TREE_CODE (exp) != PARM_DECL
       && TREE_CODE (exp) != ARRAY_REF
+      && TREE_CODE (exp) != ARRAY_RANGE_REF
       && TREE_CODE (exp) != COMPONENT_REF
       && TREE_CODE (exp) != BIT_FIELD_REF
       && TREE_CODE (exp) != INDIRECT_REF
@@ -6043,13 +6193,14 @@ expand_expr (exp, target, tmode, modifier)
 
       if (GET_MODE_CLASS (mode) == MODE_INT
          && mode > MAX_INTEGER_COMPUTATION_MODE)
-       fatal ("unsupported wide integer operation");
+       internal_error ("unsupported wide integer operation");
     }
 
   if (tmode != mode
       && TREE_CODE (exp) != INTEGER_CST
       && TREE_CODE (exp) != PARM_DECL
       && TREE_CODE (exp) != ARRAY_REF
+      && TREE_CODE (exp) != ARRAY_RANGE_REF
       && TREE_CODE (exp) != COMPONENT_REF
       && TREE_CODE (exp) != BIT_FIELD_REF
       && TREE_CODE (exp) != INDIRECT_REF
@@ -6058,7 +6209,7 @@ expand_expr (exp, target, tmode, modifier)
       && TREE_CODE (exp) != RTL_EXPR
       && GET_MODE_CLASS (tmode) == MODE_INT
       && tmode > MAX_INTEGER_COMPUTATION_MODE)
-    fatal ("unsupported wide integer operation");
+    internal_error ("unsupported wide integer operation");
 
   check_max_integer_computation_mode (exp);
 #endif
@@ -6193,12 +6344,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
@@ -6207,8 +6359,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
@@ -6222,11 +6373,11 @@ 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
-        the address is a register.  */
+        if the address is a register.  */
       if (temp != 0)
        {
          if (GET_CODE (temp) == MEM && GET_CODE (XEXP (temp, 0)) == REG)
@@ -6248,7 +6399,7 @@ expand_expr (exp, target, tmode, modifier)
              != promote_mode (type, DECL_MODE (exp), &unsignedp, 0))
            abort ();
 
-         temp = gen_rtx_SUBREG (mode, DECL_RTL (exp), 0);
+         temp = gen_lowpart_SUBREG (mode, DECL_RTL (exp));
          SUBREG_PROMOTED_VAR_P (temp) = 1;
          SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
          return temp;
@@ -6292,8 +6443,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:
@@ -6305,7 +6456,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;
@@ -6342,19 +6493,19 @@ 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)
        {
          if (mode == VOIDmode)
            temp = const0_rtx;
          else
-           {
-             temp = assign_temp (type, 3, 0, 0);
-             if (GET_CODE (temp) == MEM)
-               RTX_UNCHANGING_P (temp) = 1;
-           }
+           temp = assign_temp (build_qualified_type (type,
+                                                     (TYPE_QUALS (type)
+                                                      | TYPE_QUAL_CONST)),
+                               3, 0, 0);
 
          SAVE_EXPR_RTL (exp) = temp;
          if (!optimize && GET_CODE (temp) == REG)
@@ -6369,7 +6520,7 @@ expand_expr (exp, target, tmode, modifier)
 
          if (GET_CODE (temp) == REG && GET_MODE (temp) != mode)
            {
-             temp = gen_rtx_SUBREG (mode, SAVE_EXPR_RTL (exp), 0);
+             temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
              SUBREG_PROMOTED_VAR_P (temp) = 1;
              SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
            }
@@ -6392,7 +6543,7 @@ expand_expr (exp, target, tmode, modifier)
        {
          /* Compute the signedness and make the proper SUBREG.  */
          promote_mode (type, mode, &unsignedp, 0);
-         temp = gen_rtx_SUBREG (mode, SAVE_EXPR_RTL (exp), 0);
+         temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
          SUBREG_PROMOTED_VAR_P (temp) = 1;
          SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
          return temp;
@@ -6493,13 +6644,15 @@ expand_expr (exp, target, tmode, modifier)
       return const0_rtx;
 
     case EXIT_EXPR:
-      expand_exit_loop_if_false (NULL_PTR,
+      expand_exit_loop_if_false (NULL,
                                 invert_truthvalue (TREE_OPERAND (exp, 0)));
       return const0_rtx;
 
     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.  */
+      do_pending_stack_adjust ();
       emit_label (label_rtx (LABELED_BLOCK_LABEL (exp)));
       return const0_rtx;
 
@@ -6535,7 +6688,7 @@ expand_expr (exp, target, tmode, modifier)
        /* If VARS have not yet been expanded, expand them now.  */
        while (vars)
          {
-           if (DECL_RTL (vars) == 0)
+           if (!DECL_RTL_SET_P (vars))
              {
                vars_need_expansion = 1;
                expand_decl (vars);
@@ -6597,36 +6750,23 @@ 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
        {
          /* Handle calls that pass values in multiple non-contiguous
             locations.  The Irix 6 ABI has examples of this.  */
          if (target == 0 || ! safe_from_p (target, exp, 1)
              || GET_CODE (target) == PARALLEL)
-           {
-             if (mode != BLKmode && ! TREE_ADDRESSABLE (exp))
-               target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
-             else
-               target = assign_temp (type, 0, 1, 1);
-           }
-
-         if (TREE_READONLY (exp))
-           {
-             if (GET_CODE (target) == MEM)
-               target = copy_rtx (target);
-
-             RTX_UNCHANGING_P (target) = 1;
-           }
+           target
+             = assign_temp (build_qualified_type (type,
+                                                  (TYPE_QUALS (type)
+                                                   | (TREE_READONLY (exp)
+                                                      * TYPE_QUAL_CONST))),
+                            TREE_ADDRESSABLE (exp), 1, 1);
 
          store_constructor (exp, target, TYPE_ALIGN (TREE_TYPE (exp)), 0,
                             int_size_in_bytes (TREE_TYPE (exp)));
@@ -6685,8 +6825,7 @@ expand_expr (exp, target, tmode, modifier)
        /* 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.  */
-       if (modifier == EXPAND_MEMORY_USE_WO
-           && TREE_CODE (type) == RECORD_TYPE && readonly_fields_p (type))
+       if (modifier == EXPAND_MEMORY_USE_WO && readonly_fields_p (type))
          RTX_UNCHANGING_P (temp) = 1;
 
        return temp;
@@ -6719,7 +6858,8 @@ expand_expr (exp, target, tmode, modifier)
           Don't fold if this is for wide characters since it's too
           difficult to do correctly and this is a very rare case.  */
 
-       if (TREE_CODE (array) == STRING_CST
+       if (modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_INITIALIZER
+           && TREE_CODE (array) == STRING_CST
            && TREE_CODE (index) == INTEGER_CST
            && compare_tree_int (index, TREE_STRING_LENGTH (array)) < 0
            && GET_MODE_CLASS (mode) == MODE_INT
@@ -6732,7 +6872,8 @@ expand_expr (exp, target, tmode, modifier)
           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)
+       if (modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_INITIALIZER
+           && TREE_CODE (array) == CONSTRUCTOR && ! TREE_SIDE_EFFECTS (array)
            && TREE_CODE (index) == INTEGER_CST
            && 0 > compare_tree_int (index,
                                     list_length (CONSTRUCTOR_ELTS
@@ -6751,6 +6892,8 @@ expand_expr (exp, target, tmode, modifier)
          }
 
        else if (optimize >= 1
+                && modifier != EXPAND_CONST_ADDRESS
+                && modifier != EXPAND_INITIALIZER
                 && TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
                 && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
                 && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK)
@@ -6769,7 +6912,7 @@ expand_expr (exp, target, tmode, modifier)
                         elem = TREE_CHAIN (elem))
                      ;
 
-                   if (elem)
+                   if (elem && !TREE_SIDE_EFFECTS (TREE_VALUE (elem)))
                      return expand_expr (fold (TREE_VALUE (elem)), target,
                                          tmode, ro_modifier);
                  }
@@ -6793,11 +6936,12 @@ expand_expr (exp, target, tmode, modifier)
 
     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 (code != ARRAY_REF
+      if (code == COMPONENT_REF
          && TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR
          && TREE_CST_RTL (TREE_OPERAND (exp, 0)) == 0)
        {
@@ -6895,18 +7039,32 @@ expand_expr (exp, target, tmode, modifier)
          {
            rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
 
-           /* If this object is in memory, put it into a register.
+           /* 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)
              {
-               rtx memloc = assign_temp (TREE_TYPE (tem), 1, 1, 1);
-
-               mark_temp_addr_taken (memloc);
-               emit_move_insn (memloc, op0);
-               op0 = memloc;
+               /* If the operand is a SAVE_EXPR, we can deal with this by
+                  forcing the SAVE_EXPR into memory.  */
+               if (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR)
+                 {
+                   put_var_into_stack (TREE_OPERAND (exp, 0));
+                   op0 = SAVE_EXPR_RTL (TREE_OPERAND (exp, 0));
+                 }
+               else
+                 {
+                   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)
@@ -6931,16 +7089,15 @@ expand_expr (exp, target, tmode, modifier)
                && (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
                && alignment == 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;
              }
 
@@ -6990,34 +7147,30 @@ expand_expr (exp, target, tmode, modifier)
           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.  */
+          storing into memory, and changing the mode to BLKmode.  */
        if (mode1 == VOIDmode
            || GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
-           || (modifier != EXPAND_CONST_ADDRESS
-               && modifier != EXPAND_INITIALIZER
-               && ((mode1 != BLKmode && ! direct_load[(int) mode1]
-                    && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
-                    && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
-                   /* 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)
-                       && ((TYPE_ALIGN (TREE_TYPE (tem))
-                            < GET_MODE_ALIGNMENT (mode))
-                           || (bitpos % GET_MODE_ALIGNMENT (mode) != 0)))
-                   /* If the type and the field are a constant size and the
-                      size of the type isn't the same size as the bitfield,
-                      we must use bitfield operations.  */
-                   || ((bitsize >= 0
-                        && (TREE_CODE (TYPE_SIZE (TREE_TYPE (exp)))
-                            == INTEGER_CST)
-                        && 0 != compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)),
-                                                  bitsize)))))
-           || (modifier != EXPAND_CONST_ADDRESS
-               && modifier != EXPAND_INITIALIZER
-               && mode == BLKmode
+           || (mode1 != BLKmode && ! direct_load[(int) mode1]
+               && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
+               && 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)
+               && ((TYPE_ALIGN (TREE_TYPE (tem))
+                    < GET_MODE_ALIGNMENT (mode))
+                   || (bitpos % GET_MODE_ALIGNMENT (mode) != 0)))
+           /* If the type and the field are a constant size and the
+              size of the type isn't the same size as the bitfield,
+              we must use bitfield operations.  */
+           || (bitsize >= 0
+               && (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)))
@@ -7039,9 +7192,7 @@ 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);
 
@@ -7077,13 +7228,13 @@ expand_expr (exp, target, tmode, modifier)
 
            if (mode == BLKmode)
              {
-               rtx new = assign_stack_temp (ext_mode,
-                                            bitsize / BITS_PER_UNIT, 0);
+               tree nt = build_qualified_type (type_for_mode (ext_mode, 0),
+                                               TYPE_QUAL_CONST);
+               rtx new = assign_temp (nt, 0, 1, 1);
 
                emit_move_insn (new, op0);
                op0 = copy_rtx (new);
                PUT_MODE (op0, BLKmode);
-               MEM_SET_IN_STRUCT_P (op0, 1);
              }
 
            return op0;
@@ -7097,18 +7248,9 @@ 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);
 
        set_mem_attributes (op0, exp, 0);
        if (GET_CODE (XEXP (op0, 0)) == REG)
@@ -7238,16 +7380,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:
       {
@@ -7303,17 +7445,12 @@ expand_expr (exp, target, tmode, modifier)
                                modifier);
 
          if (target == 0)
-           {
-             if (mode != BLKmode)
-               target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
-             else
-               target = assign_temp (type, 0, 1, 1);
-           }
+           target = assign_temp (type, 0, 1, 1);
 
          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.  */
@@ -7321,7 +7458,7 @@ expand_expr (exp, target, tmode, modifier)
                         MIN ((int_size_in_bytes (TREE_TYPE
                                                  (TREE_OPERAND (exp, 0)))
                               * BITS_PER_UNIT),
-                             GET_MODE_BITSIZE (mode)),
+                             (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);
@@ -7709,7 +7846,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:
@@ -7974,21 +8121,21 @@ expand_expr (exp, target, tmode, modifier)
          && (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0))
              == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 2), 0))))
        {
-         tree true = TREE_OPERAND (TREE_OPERAND (exp, 1), 0);
-         tree false = TREE_OPERAND (TREE_OPERAND (exp, 2), 0);
-
-         if ((TREE_CODE_CLASS (TREE_CODE (true)) == '2'
-              && operand_equal_p (false, TREE_OPERAND (true, 0), 0))
-             || (TREE_CODE_CLASS (TREE_CODE (false)) == '2'
-                 && operand_equal_p (true, TREE_OPERAND (false, 0), 0))
-             || (TREE_CODE_CLASS (TREE_CODE (true)) == '1'
-                 && operand_equal_p (false, TREE_OPERAND (true, 0), 0))
-             || (TREE_CODE_CLASS (TREE_CODE (false)) == '1'
-                 && operand_equal_p (true, TREE_OPERAND (false, 0), 0)))
+         tree iftrue = TREE_OPERAND (TREE_OPERAND (exp, 1), 0);
+         tree iffalse = TREE_OPERAND (TREE_OPERAND (exp, 2), 0);
+
+         if ((TREE_CODE_CLASS (TREE_CODE (iftrue)) == '2'
+              && operand_equal_p (iffalse, TREE_OPERAND (iftrue, 0), 0))
+             || (TREE_CODE_CLASS (TREE_CODE (iffalse)) == '2'
+                 && operand_equal_p (iftrue, TREE_OPERAND (iffalse, 0), 0))
+             || (TREE_CODE_CLASS (TREE_CODE (iftrue)) == '1'
+                 && operand_equal_p (iffalse, TREE_OPERAND (iftrue, 0), 0))
+             || (TREE_CODE_CLASS (TREE_CODE (iffalse)) == '1'
+                 && operand_equal_p (iftrue, TREE_OPERAND (iffalse, 0), 0)))
            return expand_expr (build1 (NOP_EXPR, type,
-                                       build (COND_EXPR, TREE_TYPE (true),
+                                       build (COND_EXPR, TREE_TYPE (iftrue),
                                               TREE_OPERAND (exp, 0),
-                                              true, false)),
+                                              iftrue, iffalse)),
                                target, tmode, modifier);
        }
 
@@ -8068,8 +8215,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 ();
@@ -8286,7 +8433,7 @@ expand_expr (exp, target, tmode, modifier)
 
        if (target == 0)
          {
-           if (DECL_RTL (slot) != 0)
+           if (DECL_RTL_SET_P (slot))
              {
                target = DECL_RTL (slot);
                /* If we have already expanded the slot, so don't do
@@ -8299,7 +8446,7 @@ expand_expr (exp, target, tmode, modifier)
                target = assign_temp (type, 2, 0, 1);
                /* All temp slots at this level must not conflict.  */
                preserve_temp_slots (target);
-               DECL_RTL (slot) = target;
+               SET_DECL_RTL (slot, target);
                if (TREE_ADDRESSABLE (slot))
                  put_var_into_stack (slot);
 
@@ -8325,7 +8472,7 @@ expand_expr (exp, target, tmode, modifier)
            /* If we have already assigned it space, use that space,
               not target that we were passed in, as our target
               parameter is only a hint.  */
-           if (DECL_RTL (slot) != 0)
+           if (DECL_RTL_SET_P (slot))
              {
                target = DECL_RTL (slot);
                /* If we have already expanded the slot, so don't do
@@ -8335,7 +8482,7 @@ expand_expr (exp, target, tmode, modifier)
              }
            else
              {
-               DECL_RTL (slot) = target;
+               SET_DECL_RTL (slot, target);
                /* If we must have an addressable slot, then make sure that
                   the RTL that we just stored in slot is OK.  */
                if (TREE_ADDRESSABLE (slot))
@@ -8363,8 +8510,10 @@ expand_expr (exp, target, tmode, modifier)
 
        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));
+         noncopied_parts
+           = init_noncopied_parts (stabilize_reference (lhs),
+                                   TYPE_NONCOPIED_PARTS (lhs_type));
+
        while (noncopied_parts != 0)
          {
            expand_assignment (TREE_VALUE (noncopied_parts),
@@ -8390,12 +8539,6 @@ expand_expr (exp, target, tmode, modifier)
 
        temp = 0;
 
-       if (TREE_CODE (lhs) != VAR_DECL
-           && TREE_CODE (lhs) != RESULT_DECL
-           && TREE_CODE (lhs) != PARM_DECL
-           && ! (TREE_CODE (lhs) == INDIRECT_REF
-                 && TYPE_READONLY (TREE_TYPE (TREE_OPERAND (lhs, 0)))))
-
        /* Check for |= or &= of a bitfield of size one into another bitfield
           of size 1.  In this case, (unless we need the result of the
           assignment) we can do this more efficiently with a
@@ -8430,8 +8573,9 @@ expand_expr (exp, target, tmode, modifier)
 
        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));
+         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)
@@ -8492,7 +8636,9 @@ expand_expr (exp, target, tmode, modifier)
          if (ignore)
            return op0;
 
-         op0 = protect_from_queue (op0, 0);
+         /* Pass 1 for MODIFY, so that protect_from_queue doesn't get
+            clever and returns a REG when given a MEM.  */
+         op0 = protect_from_queue (op0, 1);
 
          /* We would like the object in memory.  If it is a constant, we can
             have it be statically allocated into memory.  For a non-constant,
@@ -8514,7 +8660,10 @@ expand_expr (exp, target, tmode, modifier)
              /* If this object is in a register, it must be not
                 be BLKmode.  */
              tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
-             rtx memloc = assign_temp (inner_type, 1, 1, 1);
+             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)
@@ -8659,7 +8808,7 @@ expand_expr (exp, target, tmode, modifier)
 
        op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
 
-       expand_eh_region_end (handler);
+       expand_eh_region_end_cleanup (handler);
 
        return op0;
       }
@@ -8706,23 +8855,12 @@ expand_expr (exp, target, tmode, modifier)
        return const0_rtx;
       }
 
-    case POPDCC_EXPR:
-      {
-       rtx dcc = get_dynamic_cleanup_chain ();
-       emit_move_insn (dcc, validize_mem (gen_rtx_MEM (Pmode, dcc)));
-       return const0_rtx;
-      }
-
-    case POPDHC_EXPR:
-      {
-       rtx dhc = get_dynamic_handler_chain ();
-       emit_move_insn (dhc, validize_mem (gen_rtx_MEM (Pmode, dhc)));
-       return const0_rtx;
-      }
-
     case VA_ARG_EXPR:
       return expand_builtin_va_arg (TREE_OPERAND (exp, 0), type);
 
+    case EXC_PTR_EXPR:
+      return get_exception_pointer (cfun);
+
     default:
       return (*lang_expand_expr) (exp, original_target, tmode, modifier);
     }
@@ -8853,11 +8991,12 @@ expand_expr_unaligned (exp, palign)
 
     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) != ARRAY_REF
+      if (TREE_CODE (exp) == COMPONENT_REF
          && TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR
          && TREE_CST_RTL (TREE_OPERAND (exp, 0)) == 0)
        {
@@ -8914,7 +9053,10 @@ expand_expr_unaligned (exp, palign)
            if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
                || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
              {
-               rtx memloc = assign_temp (TREE_TYPE (tem), 1, 1, 1);
+               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);
@@ -8990,14 +9132,13 @@ expand_expr_unaligned (exp, palign)
                    || 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);
              }
            else
              {
-               rtx new = assign_stack_temp (ext_mode,
-                                            bitsize / BITS_PER_UNIT, 0);
+               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,
@@ -9023,11 +9164,9 @@ expand_expr_unaligned (exp, palign)
          }
        else
          /* Get a reference to just this component.  */
-         op0 = change_address (op0, mode1,
-                               plus_constant (XEXP (op0, 0),
-                                              (bitpos / BITS_PER_UNIT)));
+         op0 = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
 
-       MEM_ALIAS_SET (op0) = get_alias_set (exp);
+       set_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.  */
@@ -9266,7 +9405,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);
@@ -9425,7 +9564,8 @@ do_jump (exp, if_false_label, if_true_label)
     case NOP_EXPR:
       if (TREE_CODE (TREE_OPERAND (exp, 0)) == COMPONENT_REF
          || TREE_CODE (TREE_OPERAND (exp, 0)) == BIT_FIELD_REF
-         || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_REF)
+         || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_REF
+         || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_RANGE_REF)
        goto normal;
     case CONVERT_EXPR:
       /* If we are narrowing the operand, we have to do the compare in the
@@ -9531,6 +9671,7 @@ do_jump (exp, if_false_label, if_true_label)
     case COMPONENT_REF:
     case BIT_FIELD_REF:
     case ARRAY_REF:
+    case ARRAY_RANGE_REF:
       {
        HOST_WIDE_INT bitsize, bitpos;
        int unsignedp;
@@ -9781,6 +9922,39 @@ do_jump (exp, if_false_label, if_true_label)
       }
       break;
 
+      /* Special case:
+               __builtin_expect (<test>, 0)    and
+               __builtin_expect (<test>, 1)
+
+        We need to do this here, so that <test> is not converted to a SCC
+        operation on machines that use condition code registers and COMPARE
+        like the PowerPC, and then the jump is done based on whether the SCC
+        operation produced a 1 or 0.  */
+    case CALL_EXPR:
+      /* Check for a built-in function.  */
+      if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR)
+       {
+         tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+         tree arglist = TREE_OPERAND (exp, 1);
+
+         if (TREE_CODE (fndecl) == FUNCTION_DECL
+             && DECL_BUILT_IN (fndecl)
+             && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
+             && arglist != NULL_TREE
+             && TREE_CHAIN (arglist) != NULL_TREE)
+           {
+             rtx seq = expand_builtin_expect_jump (exp, if_false_label,
+                                                   if_true_label);
+
+             if (seq != NULL_RTX)
+               {
+                 emit_insn (seq);
+                 return;
+               }
+           }
+       }
+      /* fall through and generate the normal code.  */
+
     default:
     normal:
       temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
@@ -9797,7 +9971,9 @@ do_jump (exp, if_false_label, if_true_label)
       /* Do any postincrements in the expression that was tested.  */
       emit_queue ();
 
-      if (GET_CODE (temp) == CONST_INT || GET_CODE (temp) == LABEL_REF)
+      if (GET_CODE (temp) == CONST_INT 
+         || (GET_CODE (temp) == CONST_DOUBLE && GET_MODE (temp) == VOIDmode)
+         || GET_CODE (temp) == LABEL_REF)
        {
          rtx target = temp == const0_rtx ? if_false_label : if_true_label;
          if (target)
@@ -10008,8 +10184,7 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
   /* If one operand is constant, make it the second one.  Only do this
      if the other operand is not constant as well.  */
 
-  if ((CONSTANT_P (op0) && ! CONSTANT_P (op1))
-      || (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT))
+  if (swap_commutative_operands_p (op0, op1))
     {
       tem = op0;
       op0 = op1;
@@ -10091,8 +10266,7 @@ do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, size, align,
   /* If one operand is constant, make it the second one.  Only do this
      if the other operand is not constant as well.  */
 
-  if ((CONSTANT_P (op0) && ! CONSTANT_P (op1))
-      || (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT))
+  if (swap_commutative_operands_p (op0, op1))
     {
       tem = op0;
       op0 = op1;
@@ -10538,11 +10712,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 */
+
+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, 0, 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);
 
-/* INDEX is the value being switched on, with the lowest value
+  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.
@@ -10551,7 +10826,7 @@ 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;
@@ -10613,4 +10888,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;
+}