OSDN Git Service

* c-typeck.c (build_c_cast): Use TYPE_MAIN_VARIANT when checking
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index d193242..7fb0654 100644 (file)
@@ -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"
@@ -174,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
@@ -397,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
@@ -423,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)
@@ -1361,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);
@@ -1387,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
@@ -1396,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
@@ -1416,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;
 
@@ -1493,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)
@@ -1550,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)
        {
@@ -1573,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)));
@@ -1744,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);
+         make_decl_rtl (fn, NULL);
          assemble_external (fn);
        }
 
@@ -1935,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++)
     {
@@ -1964,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,8 +2020,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
@@ -2358,7 +2390,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);
@@ -2644,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);
+             make_decl_rtl (fn, NULL);
              assemble_external (fn);
            }
 
@@ -3078,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.  */
@@ -3103,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
@@ -3110,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.
@@ -3213,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,
@@ -3223,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)
            {
@@ -3477,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
        {
@@ -3493,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)
        {
@@ -3607,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;
@@ -3876,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),
@@ -4075,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);
@@ -5072,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;
 
@@ -5209,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;
@@ -5254,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.
@@ -5359,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
@@ -5382,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,
@@ -6038,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)
@@ -6052,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;
        }
       ;
@@ -6071,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
@@ -6089,6 +6175,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
@@ -6265,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)
@@ -6287,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;
@@ -6407,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;
            }
@@ -6430,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;
@@ -6531,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;
 
@@ -6747,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
@@ -6760,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
@@ -6779,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)
@@ -6821,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)
        {
@@ -6923,7 +7017,7 @@ 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.  */
@@ -7021,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)))
@@ -8389,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),
@@ -8450,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)
@@ -8512,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,
@@ -8682,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;
       }
@@ -8729,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);
     }
@@ -8876,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)
        {
@@ -9452,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
@@ -9558,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;
@@ -10037,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;
@@ -10120,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;