OSDN Git Service

* stor-layout.c (layout_type): Complain if an array's size can
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index 61309ae..e8774e4 100644 (file)
@@ -2,22 +2,22 @@
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
    2000, 2001 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -33,6 +33,8 @@ Boston, MA 02111-1307, USA.  */
 #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"
@@ -172,7 +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
@@ -384,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)
@@ -422,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)
@@ -1382,13 +1392,12 @@ convert_modes (mode, oldmode, x, unsignedp)
 #define MOVE_MAX_PIECES   MOVE_MAX
 #endif
 
-/* Generate several move instructions to copy LEN bytes
-   from block FROM to block TO.  (These are MEM rtx's with BLKmode).
-   The caller must pass FROM and TO
-    through protect_from_queue before calling.
+/* Generate several move instructions to copy LEN bytes from block FROM to
+   block TO.  (These are MEM rtx's with BLKmode).  The caller must pass FROM
+   and TO through protect_from_queue before calling.
 
-   When TO is NULL, the emit_single_push_insn is used to push the
-   FROM to stack.
+   If PUSH_ROUNDING is defined and TO is NULL, emit_single_push_insn is
+   used to push FROM to the stack.
 
    ALIGN is maximum alignment we can assume.  */
 
@@ -1511,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)
@@ -1561,7 +1570,7 @@ move_by_pieces_1 (genfun, mode, data)
      struct move_by_pieces *data;
 {
   unsigned int size = GET_MODE_SIZE (mode);
-  rtx to1, from1;
+  rtx to1 = NULL_RTX, from1;
 
   while (data->len >= size)
     {
@@ -1572,22 +1581,20 @@ move_by_pieces_1 (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 (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)));
@@ -1597,7 +1604,13 @@ move_by_pieces_1 (genfun, mode, data)
       if (data->to)
        emit_insn ((*genfun) (to1, from1));
       else
-       emit_single_push_insn (mode, from1, NULL);
+       {
+#ifdef PUSH_ROUNDING
+         emit_single_push_insn (mode, from1, NULL);
+#else
+         abort ();
+#endif
+       }
 
       if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
        emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
@@ -1768,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);
+         TREE_NOTHROW (fn) = 1;
+         make_decl_rtl (fn, NULL);
          assemble_external (fn);
        }
 
@@ -1875,8 +1889,7 @@ move_block_from_reg (regno, x, nregs, size)
   if (size <= UNITS_PER_WORD
       && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode)
     {
-      emit_move_insn (change_address (x, mode, NULL),
-                     gen_rtx_REG (mode, regno));
+      emit_move_insn (adjust_address (x, mode, 0), gen_rtx_REG (mode, regno));
       return;
     }
 
@@ -1959,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++)
     {
@@ -1988,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)
@@ -1995,10 +2012,7 @@ 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)
        {
@@ -2011,8 +2025,7 @@ emit_group_load (dst, orig_src, ssize, align)
          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
@@ -2119,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 ();
@@ -2192,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.  */
@@ -2382,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);
@@ -2507,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,
@@ -2650,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.  */
@@ -2668,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);
+             TREE_NOTHROW (fn) = 1;
+             make_decl_rtl (fn, NULL);
              assemble_external (fn);
            }
 
@@ -2744,13 +2755,13 @@ emit_move_insn (x, y)
           && ! push_operand (x, GET_MODE (x)))
          || (flag_force_addr
              && CONSTANT_ADDRESS_P (XEXP (x, 0)))))
-    x = change_address (x, VOIDmode, XEXP (x, 0));
+    x = validize_mem (x);
 
   if (GET_CODE (y) == MEM
       && (! memory_address_p (GET_MODE (y), XEXP (y, 0))
          || (flag_force_addr
              && CONSTANT_ADDRESS_P (XEXP (y, 0)))))
-    y = change_address (y, VOIDmode, XEXP (y, 0));
+    y = validize_mem (y);
 
   if (mode == BLKmode)
     abort ();
@@ -2900,7 +2911,7 @@ emit_move_insn_1 (x, y)
                    {
                      rtx mem = assign_stack_temp (reg_mode,
                                                   GET_MODE_SIZE (mode), 0);
-                     rtx cmem = change_address (mem, mode, NULL_RTX);
+                     rtx cmem = adjust_address (mem, mode, 0);
 
                      cfun->cannot_inline
                        = N_("function using short complex types cannot be inline");
@@ -2962,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
 
@@ -2971,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 ();
 
@@ -3070,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);
@@ -3122,25 +3147,41 @@ get_push_address (size)
   return copy_to_reg (temp);
 }
 
+#ifdef PUSH_ROUNDING
+
 /* Emit single push insn.  */
+
 static void
 emit_single_push_insn (mode, x, type)
      rtx x;
      enum machine_mode mode;
      tree type;
 {
-#ifdef PUSH_ROUNDING
   rtx dest_addr;
-  int rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode));
+  unsigned rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode));
   rtx dest;
+  enum insn_code icode;
+  insn_operand_predicate_fn pred;
 
+  stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
+  /* If there is push pattern, use it.  Otherwise try old way of throwing
+     MEM representing push operation to move expander.  */
+  icode = push_optab->handlers[(int) mode].insn_code;
+  if (icode != CODE_FOR_nothing)
+    {
+      if (((pred = insn_data[(int) icode].operand[0].predicate)
+         && !((*pred) (x, mode))))
+       x = force_reg (mode, x);
+      emit_insn (GEN_FCN (icode) (x));
+      return;
+    }
   if (GET_MODE_SIZE (mode) == rounded_size)
     dest_addr = gen_rtx_fmt_e (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);
   else
     {
 #ifdef STACK_GROWS_DOWNWARD
       dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
-                               GEN_INT (-rounded_size));
+                               GEN_INT (-(HOST_WIDE_INT)rounded_size));
 #else
       dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
                                GEN_INT (rounded_size));
@@ -3150,8 +3191,6 @@ emit_single_push_insn (mode, x, type)
 
   dest = gen_rtx_MEM (mode, dest_addr);
 
-  stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
-
   if (type != 0)
     {
       set_mem_attributes (dest, type, 1);
@@ -3159,13 +3198,11 @@ emit_single_push_insn (mode, x, type)
          outgoing arguments and we cannot allow reordering of reads
          from function arguments with stores to outgoing arguments
          of sibling calls.  */
-      MEM_ALIAS_SET (dest) = 0;
+      set_mem_alias_set (dest, 0);
     }
   emit_move_insn (dest, x);
-#else
-  abort();
-#endif
 }
+#endif
 
 /* Generate code to push X onto the stack, assuming it has mode MODE and
    type TYPE.
@@ -3174,7 +3211,7 @@ emit_single_push_insn (mode, x, type)
    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.
@@ -3229,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);
 
@@ -3254,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.
@@ -3277,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,
@@ -3377,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.  */
@@ -3560,7 +3598,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
                 outgoing arguments and we cannot allow reordering of reads
                 from function arguments with stores to outgoing arguments
                 of sibling calls.  */
-             MEM_ALIAS_SET (dest) = 0;
+             set_mem_alias_set (dest, 0);
            }
 
          emit_move_insn (dest, x);
@@ -3666,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;
@@ -3713,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;
            }
 
@@ -3798,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));
@@ -3887,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.  */
@@ -4447,13 +4482,11 @@ 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
@@ -4461,7 +4494,7 @@ store_constructor_field (target, bitsize, bitpos,
       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);
     }
@@ -4537,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
@@ -4682,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)
@@ -4748,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));
 
@@ -4979,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
@@ -5131,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;
 
@@ -5235,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);
@@ -5303,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.
@@ -5424,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
@@ -5447,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,
@@ -5645,13 +5686,12 @@ save_noncopied_parts (lhs, list)
                                                | TYPE_QUAL_CONST)),
                         0, 1, 1);
 
-       if (! memory_address_p (TYPE_MODE (part_type), XEXP (target, 0)))
-         target = change_address (target, TYPE_MODE (part_type), NULL_RTX);
        parts = tree_cons (to_be_saved,
                           build (RTL_EXPR, part_type, NULL_TREE,
-                                 (tree) target),
+                                 (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;
 }
@@ -5822,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:
@@ -6103,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)
@@ -6117,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;
        }
       ;
@@ -6136,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
@@ -6154,6 +6200,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
@@ -6297,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
@@ -6311,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
@@ -6326,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)
@@ -6396,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:
@@ -6409,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;
@@ -6446,8 +6493,9 @@ expand_expr (exp, target, tmode, modifier)
            }
          if (temp == 0 || GET_CODE (temp) != MEM)
            abort ();
-         return change_address (temp, mode,
-                                fix_lexical_addr (XEXP (temp, 0), exp));
+         return
+           replace_equiv_address (temp,
+                                  fix_lexical_addr (XEXP (temp, 0), exp));
        }
       if (SAVE_EXPR_RTL (exp) == 0)
        {
@@ -6596,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;
 
@@ -6700,13 +6750,9 @@ expand_expr (exp, target, tmode, modifier)
 
          if (modifier != EXPAND_CONST_ADDRESS
              && modifier != EXPAND_INITIALIZER
-             && modifier != EXPAND_SUM
-             && (! memory_address_p (GET_MODE (constructor),
-                                     XEXP (constructor, 0))
-                 || (flag_force_addr
-                     && GET_CODE (XEXP (constructor, 0)) != REG)))
-           constructor = change_address (constructor, VOIDmode,
-                                         XEXP (constructor, 0));
+             && modifier != EXPAND_SUM)
+           constructor = validize_mem (constructor);
+
          return constructor;
        }
       else
@@ -6812,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
@@ -6825,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
@@ -6844,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)
@@ -6862,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);
                  }
@@ -6886,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)
        {
@@ -6988,21 +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)
              {
-               tree nt = build_qualified_type (TREE_TYPE (tem),
-                                               (TYPE_QUALS (TREE_TYPE (tem))
-                                                | TYPE_QUAL_CONST));
-               rtx memloc = assign_temp (nt, 1, 1, 1);
+               /* 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;
+                   mark_temp_addr_taken (memloc);
+                   emit_move_insn (memloc, op0);
+                   op0 = memloc;
+                 }
              }
 
            if (GET_CODE (op0) != MEM)
@@ -7027,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;
              }
 
@@ -7086,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)))
@@ -7135,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);
 
@@ -7193,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)
@@ -7334,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:
       {
@@ -7404,7 +7450,7 @@ expand_expr (exp, target, tmode, modifier)
          if (GET_CODE (target) == MEM)
            /* Store data into beginning of memory target.  */
            store_expr (TREE_OPERAND (exp, 0),
-                       change_address (target, TYPE_MODE (valtype), 0), 0);
+                       adjust_address (target, TYPE_MODE (valtype), 0), 0);
 
          else if (GET_CODE (target) == REG)
            /* Store this field into a union of the proper type.  */
@@ -7800,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:
@@ -8159,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 ();
@@ -8454,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),
@@ -8515,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)
@@ -8577,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,
@@ -8798,7 +8859,7 @@ expand_expr (exp, target, tmode, modifier)
       return expand_builtin_va_arg (TREE_OPERAND (exp, 0), type);
 
     case EXC_PTR_EXPR:
-      return get_exception_pointer ();
+      return get_exception_pointer (cfun);
 
     default:
       return (*lang_expand_expr) (exp, original_target, tmode, modifier);
@@ -8930,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)
        {
@@ -9070,9 +9132,7 @@ 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
              {
@@ -9104,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.  */
@@ -9347,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);
@@ -9506,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
@@ -9612,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;
@@ -9862,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);
@@ -10091,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;
@@ -10174,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;
@@ -10621,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);
+
+  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);
 
-/* INDEX is the value being switched on, with the lowest value
+  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.
@@ -10634,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;
@@ -10696,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;
+}