OSDN Git Service

* c-typeck.c (build_c_cast): Use TYPE_MAIN_VARIANT when checking
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index 35ccf03..7fb0654 100644 (file)
@@ -1,6 +1,6 @@
 /* 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.
 
@@ -30,8 +30,6 @@ 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"
@@ -39,25 +37,11 @@ Boston, MA 02111-1307, USA.  */
 #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.
 
@@ -127,10 +111,10 @@ struct move_by_pieces
   int reverse;
 };
 
-/* This structure is used by clear_by_pieces to describe the clear to
+/* This structure is used by store_by_pieces to describe the clear to
    be performed.  */
 
-struct clear_by_pieces
+struct store_by_pieces
 {
   rtx to;
   rtx to_addr;
@@ -138,6 +122,8 @@ struct clear_by_pieces
   int explicit_inc_to;
   unsigned HOST_WIDE_INT len;
   HOST_WIDE_INT offset;
+  rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
+  PTR constfundata;
   int reverse;
 };
 
@@ -151,11 +137,15 @@ static unsigned HOST_WIDE_INT move_by_pieces_ninsns
                                         unsigned int));
 static void move_by_pieces_1   PARAMS ((rtx (*) (rtx, ...), enum machine_mode,
                                         struct move_by_pieces *));
+static rtx clear_by_pieces_1   PARAMS ((PTR, HOST_WIDE_INT,
+                                        enum machine_mode));
 static void clear_by_pieces    PARAMS ((rtx, unsigned HOST_WIDE_INT,
                                         unsigned int));
-static void clear_by_pieces_1  PARAMS ((rtx (*) (rtx, ...),
+static void store_by_pieces_1  PARAMS ((struct store_by_pieces *,
+                                        unsigned int));
+static void store_by_pieces_2  PARAMS ((rtx (*) (rtx, ...),
                                         enum machine_mode,
-                                        struct clear_by_pieces *));
+                                        struct store_by_pieces *));
 static rtx get_subtarget       PARAMS ((rtx));
 static int is_zeros_p          PARAMS ((tree));
 static int mostly_zeros_p      PARAMS ((tree));
@@ -175,7 +165,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));
@@ -183,6 +172,7 @@ 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));
+static void emit_single_push_insn PARAMS ((enum machine_mode, rtx, tree));
 
 /* 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
@@ -207,7 +197,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.  */
@@ -406,6 +396,9 @@ protect_from_queue (x, modify)
                                QUEUED_INSN (y));
              return temp;
            }
+         /* Copy the address into a pseudo, so that the returned value
+            remains correct across calls to emit_queue.  */
+         XEXP (new, 0) = copy_to_reg (XEXP (new, 0));
          return new;
        }
       /* Otherwise, recursively protect the subexpressions of all
@@ -432,9 +425,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)
@@ -1370,7 +1365,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);
@@ -1396,6 +1391,10 @@ convert_modes (mode, oldmode, x, unsignedp)
    from block FROM to block TO.  (These are MEM rtx's with BLKmode).
    The caller must pass FROM and TO
     through protect_from_queue before calling.
+
+   When TO is NULL, the emit_single_push_insn is used to push the
+   FROM to stack.
+
    ALIGN is maximum alignment we can assume.  */
 
 void
@@ -1405,19 +1404,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
@@ -1425,8 +1441,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;
 
@@ -1502,7 +1516,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)
@@ -1559,14 +1573,17 @@ move_by_pieces_1 (genfun, mode, data)
       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 = gen_rtx_MEM (mode, data->to_addr);
+             MEM_COPY_ATTRIBUTES (to1, data->to);
+           }
+         else
+           to1 = change_address (data->to, mode,
+                                 plus_constant (data->to_addr, data->offset));
        }
-      else
-       to1 = change_address (data->to, mode,
-                             plus_constant (data->to_addr, data->offset));
 
       if (data->autinc_from)
        {
@@ -1582,7 +1599,10 @@ move_by_pieces_1 (genfun, mode, data)
       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
+       emit_single_push_insn (mode, from1, NULL);
 
       if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
        emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
@@ -1753,7 +1773,7 @@ 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);
+         make_decl_rtl (fn, NULL);
          assemble_external (fn);
        }
 
@@ -1852,6 +1872,9 @@ 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
@@ -1941,18 +1964,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++)
     {
@@ -1962,7 +1973,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;
@@ -1970,6 +1981,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)
@@ -1987,14 +2014,13 @@ emit_group_load (dst, orig_src, ssize, align)
          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
@@ -2085,7 +2111,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)
            {
@@ -2139,8 +2165,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);
     }
 
@@ -2249,6 +2277,106 @@ use_group_regs (call_fusage, regs)
     }
 }
 \f
+
+int
+can_store_by_pieces (len, constfun, constfundata, align)
+     unsigned HOST_WIDE_INT len;
+     rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
+     PTR constfundata;
+     unsigned int align;
+{
+  unsigned HOST_WIDE_INT max_size, l;
+  HOST_WIDE_INT offset = 0;
+  enum machine_mode mode, tmode;
+  enum insn_code icode;
+  int reverse;
+  rtx cst;
+
+  if (! MOVE_BY_PIECES_P (len, align))
+    return 0;
+
+  if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
+      || align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
+    align = MOVE_MAX * BITS_PER_UNIT;
+
+  /* We would first store what we can in the largest integer mode, then go to
+     successively smaller modes.  */
+
+  for (reverse = 0;
+       reverse <= (HAVE_PRE_DECREMENT || HAVE_POST_DECREMENT);
+       reverse++)
+    {
+      l = len;
+      mode = VOIDmode;
+      max_size = MOVE_MAX_PIECES + 1;
+      while (max_size > 1)
+       {
+         for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+              tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
+           if (GET_MODE_SIZE (tmode) < max_size)
+             mode = tmode;
+
+         if (mode == VOIDmode)
+           break;
+
+         icode = mov_optab->handlers[(int) mode].insn_code;
+         if (icode != CODE_FOR_nothing
+             && align >= GET_MODE_ALIGNMENT (mode))
+           {
+             unsigned int size = GET_MODE_SIZE (mode);
+
+             while (l >= size)
+               {
+                 if (reverse)
+                   offset -= size;
+
+                 cst = (*constfun) (constfundata, offset, mode);
+                 if (!LEGITIMATE_CONSTANT_P (cst))
+                   return 0;
+
+                 if (!reverse)
+                   offset += size;
+
+                 l -= size;
+               }
+           }
+
+         max_size = GET_MODE_SIZE (mode);
+       }
+
+      /* The code above should have handled everything.  */
+      if (l != 0)
+       abort ();
+    }
+
+  return 1;
+}
+
+/* Generate several move instructions to store LEN bytes generated by
+   CONSTFUN to block TO.  (A MEM rtx with BLKmode).  CONSTFUNDATA is a
+   pointer which will be passed as argument in every CONSTFUN call.
+   ALIGN is maximum alignment we can assume.  */
+
+void
+store_by_pieces (to, len, constfun, constfundata, align)
+     rtx to;
+     unsigned HOST_WIDE_INT len;
+     rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
+     PTR constfundata;
+     unsigned int align;
+{
+  struct store_by_pieces data;
+
+  if (! MOVE_BY_PIECES_P (len, align))
+    abort ();
+  to = protect_from_queue (to, 1);
+  data.constfun = constfun;
+  data.constfundata = constfundata;
+  data.len = len;
+  data.to = to;
+  store_by_pieces_1 (&data, align);
+}
+
 /* Generate several move instructions to clear LEN bytes of block TO.  (A MEM
    rtx with BLKmode).  The caller must pass TO through protect_from_queue
    before calling. ALIGN is maximum alignment we can assume.  */
@@ -2259,31 +2387,59 @@ clear_by_pieces (to, len, align)
      unsigned HOST_WIDE_INT len;
      unsigned int align;
 {
-  struct clear_by_pieces data;
-  rtx to_addr = XEXP (to, 0);
+  struct store_by_pieces data;
+
+  data.constfun = clear_by_pieces_1;
+  data.constfundata = NULL;
+  data.len = len;
+  data.to = to;
+  store_by_pieces_1 (&data, align);
+}
+
+/* Callback routine for clear_by_pieces.
+   Return const0_rtx unconditionally.  */
+
+static rtx
+clear_by_pieces_1 (data, offset, mode)
+     PTR data ATTRIBUTE_UNUSED;
+     HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  return const0_rtx;
+}
+
+/* Subroutine of clear_by_pieces and store_by_pieces.
+   Generate several move instructions to store LEN bytes of block TO.  (A MEM
+   rtx with BLKmode).  The caller must pass TO through protect_from_queue
+   before calling.  ALIGN is maximum alignment we can assume.  */
+
+static void
+store_by_pieces_1 (data, align)
+     struct store_by_pieces *data;
+     unsigned int align;
+{
+  rtx to_addr = XEXP (data->to, 0);
   unsigned HOST_WIDE_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.to = to;
-  data.autinc_to
+  data->offset = 0;
+  data->to_addr = to_addr;
+  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.explicit_inc_to = 0;
-  data.reverse
+  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;
+  if (data->reverse)
+    data->offset = data->len;
 
-  /* If copying requires more than two move insns,
+  /* If storing requires more than two move insns,
      copy addresses to registers (to make displacements shorter)
      and use post-increment if available.  */
-  if (!data.autinc_to
-      && move_by_pieces_ninsns (len, align) > 2)
+  if (!data->autinc_to
+      && move_by_pieces_ninsns (data->len, align) > 2)
     {
       /* Determine the main mode we'll be using.  */
       for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
@@ -2291,30 +2447,30 @@ clear_by_pieces (to, len, align)
        if (GET_MODE_SIZE (tmode) < max_size)
          mode = tmode;
 
-      if (USE_STORE_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_to)
+      if (USE_STORE_PRE_DECREMENT (mode) && data->reverse && ! data->autinc_to)
        {
-         data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len));
-         data.autinc_to = 1;
-         data.explicit_inc_to = -1;
+         data->to_addr = copy_addr_to_reg (plus_constant (to_addr, data->len));
+         data->autinc_to = 1;
+         data->explicit_inc_to = -1;
        }
 
-      if (USE_STORE_POST_INCREMENT (mode) && ! data.reverse
-         && ! data.autinc_to)
+      if (USE_STORE_POST_INCREMENT (mode) && ! data->reverse
+         && ! data->autinc_to)
        {
-         data.to_addr = copy_addr_to_reg (to_addr);
-         data.autinc_to = 1;
-         data.explicit_inc_to = 1;
+         data->to_addr = copy_addr_to_reg (to_addr);
+         data->autinc_to = 1;
+         data->explicit_inc_to = 1;
        }
 
-      if ( !data.autinc_to && CONSTANT_P (to_addr))
-       data.to_addr = copy_addr_to_reg (to_addr);
+      if ( !data->autinc_to && CONSTANT_P (to_addr))
+       data->to_addr = copy_addr_to_reg (to_addr);
     }
 
   if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
       || align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
     align = MOVE_MAX * BITS_PER_UNIT;
 
-  /* First move what we can in the largest integer mode, then go to
+  /* First store what we can in the largest integer mode, then go to
      successively smaller modes.  */
 
   while (max_size > 1)
@@ -2329,28 +2485,28 @@ clear_by_pieces (to, len, align)
 
       icode = mov_optab->handlers[(int) mode].insn_code;
       if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
-       clear_by_pieces_1 (GEN_FCN (icode), mode, &data);
+       store_by_pieces_2 (GEN_FCN (icode), mode, data);
 
       max_size = GET_MODE_SIZE (mode);
     }
 
   /* The code above should have handled everything.  */
-  if (data.len != 0)
+  if (data->len != 0)
     abort ();
 }
 
-/* Subroutine of clear_by_pieces.  Clear as many bytes as appropriate
+/* Subroutine of store_by_pieces_1.  Store as many bytes as appropriate
    with move instructions for mode MODE.  GENFUN is the gen_... function
    to make a move insn for that mode.  DATA has all the other info.  */
 
 static void
-clear_by_pieces_1 (genfun, mode, data)
+store_by_pieces_2 (genfun, mode, data)
      rtx (*genfun) PARAMS ((rtx, ...));
      enum machine_mode mode;
-     struct clear_by_pieces *data;
+     struct store_by_pieces *data;
 {
   unsigned int size = GET_MODE_SIZE (mode);
-  rtx to1;
+  rtx to1, cst;
 
   while (data->len >= size)
     {
@@ -2367,9 +2523,11 @@ clear_by_pieces_1 (genfun, mode, data)
                              plus_constant (data->to_addr, data->offset));
 
       if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
-       emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size)));
+       emit_insn (gen_add2_insn (data->to_addr,
+                                 GEN_INT (-(HOST_WIDE_INT) size)));
 
-      emit_insn ((*genfun) (to1, const0_rtx));
+      cst = (*data->constfun) (data->constfundata, data->offset, mode);
+      emit_insn ((*genfun) (to1, cst));
 
       if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
        emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
@@ -2402,7 +2560,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
     {
@@ -2518,7 +2676,7 @@ clear_storage (object, size, align)
              DECL_EXTERNAL (fn) = 1;
              TREE_PUBLIC (fn) = 1;
              DECL_ARTIFICIAL (fn) = 1;
-             make_decl_rtl (fn, NULL_PTR, 1);
+             make_decl_rtl (fn, NULL);
              assemble_external (fn);
            }
 
@@ -2569,6 +2727,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);
@@ -2580,7 +2740,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.  */
@@ -2600,7 +2763,13 @@ emit_move_insn (x, 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.
@@ -2616,7 +2785,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)
@@ -2636,6 +2805,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.
 
@@ -2686,17 +2901,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 = 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)
                        {
@@ -2895,11 +3110,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.  */
@@ -2920,6 +3130,51 @@ get_push_address (size)
   return copy_to_reg (temp);
 }
 
+/* Emit single push insn.  */
+static void
+emit_single_push_insn (mode, x, type)
+     rtx x;
+     enum machine_mode mode;
+     tree type;
+{
+#ifdef PUSH_ROUNDING
+  rtx dest_addr;
+  int rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode));
+  rtx dest;
+
+  if (GET_MODE_SIZE (mode) == rounded_size)
+    dest_addr = gen_rtx_fmt_e (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);
+  else
+    {
+#ifdef STACK_GROWS_DOWNWARD
+      dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+                               GEN_INT (-rounded_size));
+#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);
+
+  stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
+
+  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);
+#else
+  abort();
+#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
@@ -2927,7 +3182,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.
@@ -3030,7 +3285,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,
@@ -3040,9 +3296,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)
            {
@@ -3294,10 +3548,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
        {
@@ -3310,20 +3561,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.  */
+             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)
        {
@@ -3424,7 +3675,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;
@@ -3693,7 +3944,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),
@@ -3755,6 +4006,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)
     {
@@ -3825,7 +4077,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))
@@ -3883,7 +4143,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);
@@ -3955,7 +4215,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)
@@ -4014,9 +4275,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
                {
@@ -4202,8 +4464,14 @@ store_constructor_field (target, bitsize, bitpos,
                            plus_constant (XEXP (target, 0),
                                           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;
+
       store_constructor (exp, target, align, cleared, bitsize / BITS_PER_UNIT);
     }
   else
@@ -4286,7 +4554,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);
@@ -4408,7 +4676,8 @@ store_constructor (exp, target, align, cleared, size)
 #endif
          store_constructor_field (to_rtx, bitsize, bitpos, mode,
                                   TREE_VALUE (elt), type, align, cleared,
-                                  DECL_NONADDRESSABLE_P (field)
+                                  (DECL_NONADDRESSABLE_P (field)
+                                   && GET_CODE (to_rtx) == MEM)
                                   ? MEM_ALIAS_SET (to_rtx)
                                   : get_alias_set (TREE_TYPE (field)));
        }
@@ -4563,10 +4832,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)
                    {
@@ -4640,6 +4909,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));
 
@@ -4784,9 +5054,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);
            }
 
@@ -4868,6 +5140,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;
 
@@ -4885,15 +5162,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,
@@ -5004,7 +5282,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;
@@ -5049,8 +5333,8 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
 }
 \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.
@@ -5154,12 +5438,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
@@ -5177,8 +5463,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,
@@ -5257,10 +5542,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.  */
 
@@ -5369,7 +5654,12 @@ 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);
+       rtx target
+         = assign_temp (build_qualified_type (part_type,
+                                              (TYPE_QUALS (part_type)
+                                               | TYPE_QUAL_CONST)),
+                        0, 1, 1);
+
        if (! memory_address_p (TYPE_MODE (part_type), XEXP (target, 0)))
          target = change_address (target, TYPE_MODE (part_type), NULL_RTX);
        parts = tree_cons (to_be_saved,
@@ -5422,10 +5712,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
@@ -5440,31 +5727,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)
@@ -5474,17 +5744,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':
@@ -5520,11 +5808,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;
 
@@ -5558,37 +5848,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:
@@ -5616,7 +5889,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;
@@ -5635,10 +5909,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.  */
@@ -5680,6 +5955,7 @@ var_rtx (exp)
 }
 
 #ifdef MAX_INTEGER_COMPUTATION_MODE
+
 void
 check_max_integer_computation_mode (exp)
      tree exp;
@@ -5705,7 +5981,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.  */
@@ -5714,7 +5990,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.  */
@@ -5723,36 +5999,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.
@@ -5862,10 +6118,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)
@@ -5876,9 +6134,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;
        }
       ;
@@ -5895,6 +6156,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
@@ -5906,13 +6168,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
@@ -5921,7 +6184,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
@@ -6089,7 +6352,7 @@ expand_expr (exp, target, tmode, modifier)
                               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)
@@ -6111,7 +6374,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;
@@ -6213,11 +6476,10 @@ expand_expr (exp, target, tmode, modifier)
          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)
@@ -6232,7 +6494,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;
            }
@@ -6255,7 +6517,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;
@@ -6356,13 +6618,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;
 
@@ -6398,7 +6662,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);
@@ -6469,27 +6733,18 @@ expand_expr (exp, target, tmode, modifier)
                                          XEXP (constructor, 0));
          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)));
@@ -6548,8 +6803,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;
@@ -6582,7 +6836,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
@@ -6595,7 +6850,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
@@ -6614,6 +6870,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)
@@ -6656,11 +6914,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)
        {
@@ -6758,14 +7017,17 @@ 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);
+               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);
@@ -6853,34 +7115,28 @@ 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)
+           /* 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)))
@@ -6940,13 +7196,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;
@@ -7166,12 +7422,7 @@ 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.  */
@@ -7184,7 +7435,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);
@@ -7837,21 +8088,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);
        }
 
@@ -8149,7 +8400,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
@@ -8162,7 +8413,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);
 
@@ -8188,7 +8439,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
@@ -8198,7 +8449,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))
@@ -8226,8 +8477,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),
@@ -8253,12 +8506,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
@@ -8293,8 +8540,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)
@@ -8355,7 +8603,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,
@@ -8377,7 +8627,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)
@@ -8522,7 +8775,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;
       }
@@ -8569,23 +8822,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 ();
+
     default:
       return (*lang_expand_expr) (exp, original_target, tmode, modifier);
     }
@@ -8716,11 +8958,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)
        {
@@ -8777,7 +9020,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);
@@ -8859,8 +9105,9 @@ expand_expr_unaligned (exp, palign)
              }
            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,
@@ -9288,7 +9535,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
@@ -9394,6 +9642,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;
@@ -9660,7 +9909,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)
@@ -9871,8 +10122,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;
@@ -9954,8 +10204,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;
@@ -10054,8 +10303,22 @@ do_compare_and_jump (exp, signed_code, unsigned_code, if_false_label,
     return;
 
   op1 = expand_expr_unaligned (TREE_OPERAND (exp, 1), &align1);
+  if (TREE_CODE (TREE_OPERAND (exp, 1)) == ERROR_MARK)
+    return;
+
   type = TREE_TYPE (TREE_OPERAND (exp, 0));
   mode = TYPE_MODE (type);
+  if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
+      && (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST
+         || (GET_MODE_BITSIZE (mode)
+             > GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp,
+                                                                     1)))))))
+    {
+      /* op0 might have been replaced by promoted constant, in which
+        case the type of second argument should be used.  */
+      type = TREE_TYPE (TREE_OPERAND (exp, 1));
+      mode = TYPE_MODE (type);
+    }
   unsignedp = TREE_UNSIGNED (type);
   code = unsignedp ? unsigned_code : signed_code;