OSDN Git Service

* Makefile.in (distclean): Don't try to remove empty directories.
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index 320284c..989a5fa 100644 (file)
@@ -1,6 +1,6 @@
 /* Convert tree expression to rtl instructions, for GNU compiler.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -47,7 +47,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "langhooks.h"
 #include "intl.h"
 #include "tm_p.h"
+#include "tree-iterator.h"
+#include "tree-pass.h"
+#include "tree-flow.h"
 #include "target.h"
+#include "timevar.h"
 
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
@@ -73,11 +77,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #endif
 #endif
 
-/* Assume that case vectors are not pc-relative.  */
-#ifndef CASE_VECTOR_PC_RELATIVE
-#define CASE_VECTOR_PC_RELATIVE 0
-#endif
-
 /* Convert defined/undefined to boolean.  */
 #ifdef TARGET_MEM_FUNCTIONS
 #undef TARGET_MEM_FUNCTIONS
@@ -95,9 +94,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    the same indirect address eventually.  */
 int cse_not_expected;
 
-/* Chain of pending expressions for PLACEHOLDER_EXPR to replace.  */
-tree placeholder_list = 0;
-
 /* This structure is used by move_by_pieces to describe the move to
    be performed.  */
 struct move_by_pieces
@@ -151,7 +147,6 @@ static rtx clear_storage_via_libcall (rtx, rtx);
 static tree clear_storage_libcall_fn (int);
 static rtx compress_float_constant (rtx, rtx);
 static rtx get_subtarget (rtx);
-static int is_zeros_p (tree);
 static void store_constructor_field (rtx, unsigned HOST_WIDE_INT,
                                     HOST_WIDE_INT, enum machine_mode,
                                     tree, tree, int, int);
@@ -161,7 +156,7 @@ static rtx store_field (rtx, HOST_WIDE_INT, HOST_WIDE_INT, enum machine_mode,
 static rtx var_rtx (tree);
 
 static unsigned HOST_WIDE_INT highest_pow2_factor (tree);
-static unsigned HOST_WIDE_INT highest_pow2_factor_for_type (tree, tree);
+static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (tree, tree);
 
 static int is_aligning_offset (tree, tree);
 static rtx expand_increment (tree, int, int);
@@ -185,18 +180,6 @@ static char direct_store[NUM_MACHINE_MODES];
 
 static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
 
-/* If a memory-to-memory move would take MOVE_RATIO or more simple
-   move-instruction sequences, we will do a movstr or libcall instead.  */
-
-#ifndef MOVE_RATIO
-#if defined (HAVE_movstrqi) || defined (HAVE_movstrhi) || defined (HAVE_movstrsi) || defined (HAVE_movstrdi) || defined (HAVE_movstrti)
-#define MOVE_RATIO 2
-#else
-/* If we are optimizing for space (-Os), cut down the default move ratio.  */
-#define MOVE_RATIO (optimize_size ? 3 : 15)
-#endif
-#endif
-
 /* This macro is used to determine whether move_by_pieces should be called
    to perform a structure copy.  */
 #ifndef MOVE_BY_PIECES_P
@@ -204,18 +187,6 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
   (move_by_pieces_ninsns (SIZE, ALIGN) < (unsigned int) MOVE_RATIO)
 #endif
 
-/* If a clear memory operation would take CLEAR_RATIO or more simple
-   move-instruction sequences, we will do a clrstr or libcall instead.  */
-
-#ifndef CLEAR_RATIO
-#if defined (HAVE_clrstrqi) || defined (HAVE_clrstrhi) || defined (HAVE_clrstrsi) || defined (HAVE_clrstrdi) || defined (HAVE_clrstrti)
-#define CLEAR_RATIO 2
-#else
-/* If we are optimizing for space, cut down the default clear ratio.  */
-#define CLEAR_RATIO (optimize_size ? 3 : 15)
-#endif
-#endif
-
 /* This macro is used to determine whether clear_by_pieces should be
    called to clear storage.  */
 #ifndef CLEAR_BY_PIECES_P
@@ -241,9 +212,6 @@ enum insn_code clrstr_optab[NUM_MACHINE_MODES];
 enum insn_code cmpstr_optab[NUM_MACHINE_MODES];
 enum insn_code cmpmem_optab[NUM_MACHINE_MODES];
 
-/* Stack of EXPR_WITH_FILE_LOCATION nested expressions.  */
-struct file_stack *expr_wfl_stack;
-
 /* SLOW_UNALIGNED_ACCESS is nonzero if unaligned accesses are very slow.  */
 
 #ifndef SLOW_UNALIGNED_ACCESS
@@ -498,13 +466,30 @@ queued_subexp_p (rtx x)
     }
 }
 
-/* Perform all the pending incrementations.  */
+/* Retrieve a mark on the queue.  */
+  
+static rtx
+mark_queue (void)
+{
+  return pending_chain;
+}
 
-void
-emit_queue (void)
+/* Perform all the pending incrementations that have been enqueued
+   after MARK was retrieved.  If MARK is null, perform all the
+   pending incrementations.  */
+
+static void
+emit_insns_enqueued_after_mark (rtx mark)
 {
   rtx p;
-  while ((p = pending_chain))
+
+  /* The marked incrementation may have been emitted in the meantime
+     through a call to emit_queue.  In this case, the mark is not valid
+     anymore so do nothing.  */
+  if (mark && ! QUEUED_BODY (mark))
+    return;
+
+  while ((p = pending_chain) != mark)
     {
       rtx body = QUEUED_BODY (p);
 
@@ -531,9 +516,18 @@ emit_queue (void)
          break;
        }
 
+      QUEUED_BODY (p) = 0;
       pending_chain = QUEUED_NEXT (p);
     }
 }
+
+/* Perform all the pending incrementations.  */
+
+void
+emit_queue (void)
+{
+  emit_insns_enqueued_after_mark (NULL_RTX);
+}
 \f
 /* Copy data from FROM to TO, where the machine modes are not the same.
    Both modes may be integer, or both may be floating.
@@ -560,6 +554,11 @@ convert_move (rtx to, rtx from, int unsignedp)
   if (to_real != from_real)
     abort ();
 
+  /* If the source and destination are already the same, then there's
+     nothing to do.  */
+  if (to == from)
+    return;
+
   /* If FROM is a SUBREG that indicates that we have already done at least
      the required extension, strip it.  We don't handle such SUBREGs as
      TO here.  */
@@ -674,7 +673,7 @@ convert_move (rtx to, rtx from, int unsignedp)
       if (to_mode == full_mode)
        return;
 
-      /* else proceed to integer conversions below */
+      /* else proceed to integer conversions below */
       from_mode = full_mode;
     }
 
@@ -710,8 +709,12 @@ convert_move (rtx to, rtx from, int unsignedp)
               && ((code = can_extend_p (to_mode, word_mode, unsignedp))
                   != CODE_FOR_nothing))
        {
-         if (GET_CODE (to) == REG)
-           emit_insn (gen_rtx_CLOBBER (VOIDmode, to));
+         if (REG_P (to))
+           {
+             if (reg_overlap_mentioned_p (to, from))
+               from = force_reg (from_mode, from);
+             emit_insn (gen_rtx_CLOBBER (VOIDmode, to));
+           }
          convert_move (gen_lowpart (word_mode, to), from, unsignedp);
          emit_unop_insn (code, to,
                          gen_lowpart (word_mode, to), equiv_code);
@@ -793,7 +796,7 @@ convert_move (rtx to, rtx from, int unsignedp)
             && ! MEM_VOLATILE_P (from)
             && direct_load[(int) to_mode]
             && ! mode_dependent_address_p (XEXP (from, 0)))
-           || GET_CODE (from) == REG
+           || REG_P (from)
            || GET_CODE (from) == SUBREG))
        from = force_reg (from_mode, from);
       convert_move (to, gen_lowpart (word_mode, from), 0);
@@ -812,10 +815,10 @@ convert_move (rtx to, rtx from, int unsignedp)
             && ! MEM_VOLATILE_P (from)
             && direct_load[(int) to_mode]
             && ! mode_dependent_address_p (XEXP (from, 0)))
-           || GET_CODE (from) == REG
+           || REG_P (from)
            || GET_CODE (from) == SUBREG))
        from = force_reg (from_mode, from);
-      if (GET_CODE (from) == REG && REGNO (from) < FIRST_PSEUDO_REGISTER
+      if (REG_P (from) && REGNO (from) < FIRST_PSEUDO_REGISTER
          && ! HARD_REGNO_MODE_OK (REGNO (from), to_mode))
        from = copy_to_reg (from);
       emit_move_insn (to, gen_lowpart (to_mode, from));
@@ -983,7 +986,7 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
              || (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (oldmode)
                  && ((GET_CODE (x) == MEM && ! MEM_VOLATILE_P (x)
                       && direct_load[(int) mode])
-                     || (GET_CODE (x) == REG
+                     || (REG_P (x)
                          && (! HARD_REGISTER_P (x)
                              || HARD_REGNO_MODE_OK (REGNO (x), mode))
                          && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
@@ -1419,7 +1422,7 @@ block_move_libcall_safe_for_call_parm (void)
     tree fn, arg;
 
     fn = emit_block_move_libcall_fn (false);
-    INIT_CUMULATIVE_ARGS (args_so_far, TREE_TYPE (fn), NULL_RTX, 0);
+    INIT_CUMULATIVE_ARGS (args_so_far, TREE_TYPE (fn), NULL_RTX, 0, 3);
 
     arg = TYPE_ARG_TYPES (TREE_TYPE (fn));
     for ( ; arg != void_list_node ; arg = TREE_CHAIN (arg))
@@ -1446,6 +1449,7 @@ static bool
 emit_block_move_via_movstr (rtx x, rtx y, rtx size, unsigned int align)
 {
   rtx opalign = GEN_INT (align / BITS_PER_UNIT);
+  int save_volatile_ok = volatile_ok;
   enum machine_mode mode;
 
   /* Since this is a move insn, we don't care about volatility.  */
@@ -1495,7 +1499,7 @@ emit_block_move_via_movstr (rtx x, rtx y, rtx size, unsigned int align)
          if (pat)
            {
              emit_insn (pat);
-             volatile_ok = 0;
+             volatile_ok = save_volatile_ok;
              return true;
            }
          else
@@ -1503,7 +1507,7 @@ emit_block_move_via_movstr (rtx x, rtx y, rtx size, unsigned int align)
        }
     }
 
-  volatile_ok = 0;
+  volatile_ok = save_volatile_ok;
   return false;
 }
 
@@ -1689,8 +1693,6 @@ emit_block_move_via_loop (rtx x, rtx y, rtx size,
   y_addr = force_operand (XEXP (y, 0), NULL_RTX);
   do_pending_stack_adjust ();
 
-  emit_note (NOTE_INSN_LOOP_BEG);
-
   emit_jump (cmp_label);
   emit_label (top_label);
 
@@ -1707,13 +1709,10 @@ emit_block_move_via_loop (rtx x, rtx y, rtx size,
   if (tmp != iter)
     emit_move_insn (iter, tmp);
 
-  emit_note (NOTE_INSN_LOOP_CONT);
   emit_label (cmp_label);
 
   emit_cmp_and_jump_insns (iter, size, LT, NULL_RTX, iter_mode,
                           true, top_label);
-
-  emit_note (NOTE_INSN_LOOP_END);
 }
 \f
 /* Copy all or part of a value X into registers starting at REGNO.
@@ -1921,7 +1920,7 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
                 to be extracted.  */
              tmps[i] = XEXP (src, bytepos / slen0);
              if (! CONSTANT_P (tmps[i])
-                 && (GET_CODE (tmps[i]) != REG || GET_MODE (tmps[i]) != mode))
+                 && (!REG_P (tmps[i]) || GET_MODE (tmps[i]) != mode))
                tmps[i] = extract_bit_field (tmps[i], bytelen * BITS_PER_UNIT,
                                             (bytepos % slen0) * BITS_PER_UNIT,
                                             1, NULL_RTX, mode, mode, ssize);
@@ -1939,7 +1938,7 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
         SIMD register, which is currently broken.  While we get GCC
         to emit proper RTL for these cases, let's dump to memory.  */
       else if (VECTOR_MODE_P (GET_MODE (dst))
-              && GET_CODE (src) == REG)
+              && REG_P (src))
        {
          int slen = GET_MODE_SIZE (GET_MODE (src));
          rtx mem;
@@ -1948,8 +1947,11 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
          emit_move_insn (mem, src);
          tmps[i] = adjust_address (mem, mode, (int) bytepos);
        }
+      else if (CONSTANT_P (src) && GET_MODE (dst) != BLKmode
+               && XVECLEN (dst, 0) > 1)
+        tmps[i] = simplify_gen_subreg (mode, src, GET_MODE(dst), bytepos);
       else if (CONSTANT_P (src)
-              || (GET_CODE (src) == REG && GET_MODE (src) == mode))
+              || (REG_P (src) && GET_MODE (src) == mode))
        tmps[i] = src;
       else
        tmps[i] = extract_bit_field (src, bytelen * BITS_PER_UNIT,
@@ -2149,7 +2151,7 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
 
   if (GET_MODE (srcreg) != BLKmode
       && GET_MODE_SIZE (GET_MODE (srcreg)) < UNITS_PER_WORD)
-    srcreg = convert_to_mode (word_mode, srcreg, TREE_UNSIGNED (type));
+    srcreg = convert_to_mode (word_mode, srcreg, TYPE_UNSIGNED (type));
 
   /* If the structure doesn't take up a whole number of words, see whether
      SRCREG is padded on the left or on the right.  If it's on the left,
@@ -2208,7 +2210,7 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
 void
 use_reg (rtx *call_fusage, rtx reg)
 {
-  if (GET_CODE (reg) != REG
+  if (!REG_P (reg)
       || REGNO (reg) >= FIRST_PSEUDO_REGISTER)
     abort ();
 
@@ -2248,7 +2250,7 @@ use_group_regs (rtx *call_fusage, rtx regs)
       /* A NULL entry means the parameter goes both on the stack and in
         registers.  This can also be a MEM for targets that pass values
         partially on the stack and partially in registers.  */
-      if (reg != 0 && GET_CODE (reg) == REG)
+      if (reg != 0 && REG_P (reg))
        use_reg (call_fusage, reg);
     }
 }
@@ -2799,10 +2801,7 @@ emit_move_insn (rtx x, rtx y)
   if (mode == BLKmode || (GET_MODE (y) != mode && GET_MODE (y) != VOIDmode))
     abort ();
 
-  /* Never force constant_p_rtx to memory.  */
-  if (GET_CODE (y) == CONSTANT_P_RTX)
-    ;
-  else if (CONSTANT_P (y))
+  if (CONSTANT_P (y))
     {
       if (optimize
          && SCALAR_FLOAT_MODE_P (GET_MODE (x))
@@ -2843,7 +2842,7 @@ emit_move_insn (rtx x, rtx y)
 
   last_insn = emit_move_insn_1 (x, y);
 
-  if (y_cst && GET_CODE (x) == REG
+  if (y_cst && REG_P (x)
       && (set = single_set (last_insn)) != NULL_RTX
       && SET_DEST (set) == x
       && ! rtx_equal_p (y_cst, SET_SRC (set)))
@@ -2985,9 +2984,6 @@ emit_move_insn_1 (rtx x, rtx y)
                                                   GET_MODE_SIZE (mode), 0);
                      rtx cmem = adjust_address (mem, mode, 0);
 
-                     cfun->cannot_inline
-                       = N_("function using short complex types cannot be inline");
-
                      if (packed_dest_p)
                        {
                          rtx sreg = gen_rtx_SUBREG (reg_mode, x, 0);
@@ -3252,7 +3248,7 @@ compress_float_constant (rtx x, rtx y)
       emit_unop_insn (ic, x, trunc_y, UNKNOWN);
       last_insn = get_last_insn ();
 
-      if (GET_CODE (x) == REG)
+      if (REG_P (x))
        set_unique_reg_note (last_insn, REG_EQUAL, y);
 
       return last_insn;
@@ -3280,7 +3276,7 @@ push_block (rtx size, int extra, int below)
   size = convert_modes (Pmode, ptr_mode, size, 1);
   if (CONSTANT_P (size))
     anti_adjust_stack (plus_constant (size, extra));
-  else if (GET_CODE (size) == REG && extra == 0)
+  else if (REG_P (size) && extra == 0)
     anti_adjust_stack (size);
   else
     {
@@ -3474,9 +3470,19 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
 
       rtx temp;
       int used = partial * UNITS_PER_WORD;
-      int offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
+      int offset;
       int skip;
 
+      if (reg && GET_CODE (reg) == PARALLEL)
+       {
+         /* Use the size of the elt to compute offset.  */
+         rtx elt = XEXP (XVECEXP (reg, 0, 0), 0);
+         used = partial * GET_MODE_SIZE (GET_MODE (elt));
+         offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
+       }
+      else
+       offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
+
       if (size == 0)
        abort ();
 
@@ -3631,7 +3637,7 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
 
       /* If X is a hard register in a non-integer mode, copy it into a pseudo;
         SUBREGs of such registers are not allowed.  */
-      if ((GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER
+      if ((REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER
           && GET_MODE_CLASS (GET_MODE (x)) != MODE_INT))
        x = copy_to_reg (x);
 
@@ -3720,7 +3726,7 @@ get_subtarget (rtx x)
 {
   return ((x == 0
           /* Only registers can be subtargets.  */
-          || GET_CODE (x) != REG
+          || !REG_P (x)
           /* If the register is readonly, it can't be set more than once.  */
           || RTX_UNCHANGING_P (x)
           /* Don't use hard regs to avoid extending their life.  */
@@ -3811,8 +3817,8 @@ expand_assignment (tree to, tree from, int want_value)
            }
 
          to_rtx = offset_address (to_rtx, offset_rtx,
-                                  highest_pow2_factor_for_type (TREE_TYPE (to),
-                                                                offset));
+                                  highest_pow2_factor_for_target (to,
+                                                                  offset));
        }
 
       if (GET_CODE (to_rtx) == MEM)
@@ -3869,7 +3875,7 @@ expand_assignment (tree to, tree from, int want_value)
       return (want_value ? convert_modes (TYPE_MODE (TREE_TYPE (to)),
                                          TYPE_MODE (TREE_TYPE (from)),
                                          result,
-                                         TREE_UNSIGNED (TREE_TYPE (to)))
+                                         TYPE_UNSIGNED (TREE_TYPE (to)))
              : NULL_RTX);
     }
 
@@ -3886,7 +3892,7 @@ expand_assignment (tree to, tree from, int want_value)
   if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from, from)
       && TREE_CODE (TYPE_SIZE (TREE_TYPE (from))) == INTEGER_CST
       && ! ((TREE_CODE (to) == VAR_DECL || TREE_CODE (to) == PARM_DECL)
-           && GET_CODE (DECL_RTL (to)) == REG))
+           && REG_P (DECL_RTL (to))))
     {
       rtx value;
 
@@ -3922,7 +3928,7 @@ expand_assignment (tree to, tree from, int want_value)
 
   /* Don't move directly into a return register.  */
   if (TREE_CODE (to) == RESULT_DECL
-      && (GET_CODE (to_rtx) == REG || GET_CODE (to_rtx) == PARALLEL))
+      && (REG_P (to_rtx) || GET_CODE (to_rtx) == PARALLEL))
     {
       rtx temp;
 
@@ -3959,7 +3965,7 @@ expand_assignment (tree to, tree from, int want_value)
                           VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
                           XEXP (from_rtx, 0), Pmode,
                           convert_to_mode (TYPE_MODE (sizetype),
-                                           size, TREE_UNSIGNED (sizetype)),
+                                           size, TYPE_UNSIGNED (sizetype)),
                           TYPE_MODE (sizetype));
       else
         emit_library_call (bcopy_libfunc, LCT_NORMAL,
@@ -3967,7 +3973,7 @@ expand_assignment (tree to, tree from, int want_value)
                           XEXP (to_rtx, 0), Pmode,
                           convert_to_mode (TYPE_MODE (integer_type_node),
                                            size,
-                                           TREE_UNSIGNED (integer_type_node)),
+                                           TYPE_UNSIGNED (integer_type_node)),
                           TYPE_MODE (integer_type_node));
 
       preserve_temp_slots (to_rtx);
@@ -4016,6 +4022,8 @@ rtx
 store_expr (tree exp, rtx target, int want_value)
 {
   rtx temp;
+  rtx alt_rtl = NULL_RTX;
+  rtx mark = mark_queue ();
   int dont_return_target = 0;
   int dont_store_target = 0;
 
@@ -4135,13 +4143,13 @@ store_expr (tree exp, rtx target, int want_value)
          && INTEGRAL_TYPE_P (TREE_TYPE (exp))
          && TREE_TYPE (TREE_TYPE (exp)) == 0)
        {
-         if (TREE_UNSIGNED (TREE_TYPE (exp))
+         if (TYPE_UNSIGNED (TREE_TYPE (exp))
              != SUBREG_PROMOTED_UNSIGNED_P (target))
            exp = convert
-             ((*lang_hooks.types.signed_or_unsigned_type)
+             (lang_hooks.types.signed_or_unsigned_type
               (SUBREG_PROMOTED_UNSIGNED_P (target), TREE_TYPE (exp)), exp);
 
-         exp = convert ((*lang_hooks.types.type_for_mode)
+         exp = convert (lang_hooks.types.type_for_mode
                         (GET_MODE (SUBREG_REG (target)),
                          SUBREG_PROMOTED_UNSIGNED_P (target)),
                         exp);
@@ -4197,8 +4205,10 @@ store_expr (tree exp, rtx target, int want_value)
     }
   else
     {
-      temp = expand_expr (exp, target, GET_MODE (target),
-                         want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
+      temp = expand_expr_real (exp, target, GET_MODE (target),
+                              (want_value & 2 
+                               ? EXPAND_STACK_PARM : EXPAND_NORMAL),
+                              &alt_rtl);
       /* Return TARGET if it's a specified hardware register.
         If TARGET is a volatile mem ref, either return TARGET
         or return a reg copied *from* TARGET; ANSI requires this.
@@ -4206,7 +4216,7 @@ store_expr (tree exp, rtx target, int want_value)
         Otherwise, if TEMP is not TARGET, return TEMP
         if it is constant (for efficiency),
         or if we really want the correct value.  */
-      if (!(target && GET_CODE (target) == REG
+      if (!(target && REG_P (target)
            && REGNO (target) < FIRST_PSEUDO_REGISTER)
          && !(GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
          && ! rtx_equal_p (temp, target)
@@ -4222,10 +4232,14 @@ store_expr (tree exp, rtx target, int want_value)
       && TREE_CODE (exp) != ERROR_MARK
       && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
     temp = convert_modes (GET_MODE (target), TYPE_MODE (TREE_TYPE (exp)),
-                         temp, TREE_UNSIGNED (TREE_TYPE (exp)));
+                         temp, TYPE_UNSIGNED (TREE_TYPE (exp)));
 
   /* If value was not generated in the target, store it there.
-     Convert the value to TARGET's type first if necessary.
+     Convert the value to TARGET's type first if necessary and emit the
+     pending incrementations that have been queued when expanding EXP.
+     Note that we cannot emit the whole queue blindly because this will
+     effectively disable the POST_INC optimization later.
+
      If TEMP and TARGET compare equal according to rtx_equal_p, but
      one or both of them are volatile memory refs, we have to distinguish
      two cases:
@@ -4243,22 +4257,23 @@ store_expr (tree exp, rtx target, int want_value)
                              || side_effects_p (target))))
       && TREE_CODE (exp) != ERROR_MARK
       && ! dont_store_target
-        /* If store_expr stores a DECL whose DECL_RTL(exp) == TARGET,
-           but TARGET is not valid memory reference, TEMP will differ
-           from TARGET although it is really the same location.  */
-      && (TREE_CODE_CLASS (TREE_CODE (exp)) != 'd'
-         || target != DECL_RTL_IF_SET (exp))
+      /* If store_expr stores a DECL whose DECL_RTL(exp) == TARGET,
+        but TARGET is not valid memory reference, TEMP will differ
+        from TARGET although it is really the same location.  */
+      && !(alt_rtl && rtx_equal_p (alt_rtl, target))
       /* If there's nothing to copy, don't bother.  Don't call expr_size
         unless necessary, because some front-ends (C++) expr_size-hook
         aborts on objects that are not supposed to be bit-copied or
         bit-initialized.  */
       && expr_size (exp) != const0_rtx)
     {
+      emit_insns_enqueued_after_mark (mark);
       target = protect_from_queue (target, 1);
+      temp = protect_from_queue (temp, 0);
       if (GET_MODE (temp) != GET_MODE (target)
          && GET_MODE (temp) != VOIDmode)
        {
-         int unsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
+         int unsignedp = TYPE_UNSIGNED (TREE_TYPE (exp));
          if (dont_return_target)
            {
              /* In this case, we will return TEMP,
@@ -4299,7 +4314,7 @@ store_expr (tree exp, rtx target, int want_value)
 
              /* Copy that much.  */
              copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx,
-                                              TREE_UNSIGNED (sizetype));
+                                              TYPE_UNSIGNED (sizetype));
              emit_block_move (target, temp, copy_size_rtx,
                               (want_value & 2
                                ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
@@ -4321,7 +4336,7 @@ store_expr (tree exp, rtx target, int want_value)
 #ifdef POINTERS_EXTEND_UNSIGNED
                  if (GET_MODE (copy_size_rtx) != Pmode)
                    copy_size_rtx = convert_to_mode (Pmode, copy_size_rtx,
-                                                    TREE_UNSIGNED (sizetype));
+                                                    TYPE_UNSIGNED (sizetype));
 #endif
 
                  target = offset_address (target, copy_size_rtx,
@@ -4348,7 +4363,11 @@ store_expr (tree exp, rtx target, int want_value)
                         (want_value & 2
                          ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
       else
-       emit_move_insn (target, temp);
+       {
+         temp = force_operand (temp, target);
+         if (temp != target)
+           emit_move_insn (target, temp);
+       }
     }
 
   /* If we don't want a value, return NULL_RTX.  */
@@ -4363,7 +4382,7 @@ store_expr (tree exp, rtx target, int want_value)
   /* Return TARGET itself if it is a hard register.  */
   else if ((want_value & 1) != 0
           && GET_MODE (target) != BLKmode
-          && ! (GET_CODE (target) == REG
+          && ! (REG_P (target)
                 && REGNO (target) < FIRST_PSEUDO_REGISTER))
     return copy_to_reg (target);
 
@@ -4371,50 +4390,166 @@ store_expr (tree exp, rtx target, int want_value)
     return target;
 }
 \f
-/* Return 1 if EXP just contains zeros.  FIXME merge with initializer_zerop.  */
+/* Examine CTOR.  Discover how many scalar fields are set to nonzero
+   values and place it in *P_NZ_ELTS.  Discover how many scalar fields
+   are set to non-constant values and place it in  *P_NC_ELTS.  */
 
-static int
-is_zeros_p (tree exp)
+static void
+categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
+                           HOST_WIDE_INT *p_nc_elts)
 {
-  tree elt;
+  HOST_WIDE_INT nz_elts, nc_elts;
+  tree list;
 
-  switch (TREE_CODE (exp))
+  nz_elts = 0;
+  nc_elts = 0;
+  
+  for (list = CONSTRUCTOR_ELTS (ctor); list; list = TREE_CHAIN (list))
     {
-    case CONVERT_EXPR:
-    case NOP_EXPR:
-    case NON_LVALUE_EXPR:
-    case VIEW_CONVERT_EXPR:
-      return is_zeros_p (TREE_OPERAND (exp, 0));
+      tree value = TREE_VALUE (list);
+      tree purpose = TREE_PURPOSE (list);
+      HOST_WIDE_INT mult;
 
-    case INTEGER_CST:
-      return integer_zerop (exp);
+      mult = 1;
+      if (TREE_CODE (purpose) == RANGE_EXPR)
+       {
+         tree lo_index = TREE_OPERAND (purpose, 0);
+         tree hi_index = TREE_OPERAND (purpose, 1);
 
-    case COMPLEX_CST:
-      return
-       is_zeros_p (TREE_REALPART (exp)) && is_zeros_p (TREE_IMAGPART (exp));
+         if (host_integerp (lo_index, 1) && host_integerp (hi_index, 1))
+           mult = (tree_low_cst (hi_index, 1)
+                   - tree_low_cst (lo_index, 1) + 1);
+       }
 
-    case REAL_CST:
-      return REAL_VALUES_IDENTICAL (TREE_REAL_CST (exp), dconst0);
+      switch (TREE_CODE (value))
+       {
+       case CONSTRUCTOR:
+         {
+           HOST_WIDE_INT nz = 0, nc = 0;
+           categorize_ctor_elements_1 (value, &nz, &nc);
+           nz_elts += mult * nz;
+           nc_elts += mult * nc;
+         }
+         break;
 
-    case VECTOR_CST:
-      for (elt = TREE_VECTOR_CST_ELTS (exp); elt;
-          elt = TREE_CHAIN (elt))
-       if (!is_zeros_p (TREE_VALUE (elt)))
-         return 0;
+       case INTEGER_CST:
+       case REAL_CST:
+         if (!initializer_zerop (value))
+           nz_elts += mult;
+         break;
+       case COMPLEX_CST:
+         if (!initializer_zerop (TREE_REALPART (value)))
+           nz_elts += mult;
+         if (!initializer_zerop (TREE_IMAGPART (value)))
+           nz_elts += mult;
+         break;
+       case VECTOR_CST:
+         {
+           tree v;
+           for (v = TREE_VECTOR_CST_ELTS (value); v; v = TREE_CHAIN (v))
+             if (!initializer_zerop (TREE_VALUE (v)))
+               nz_elts += mult;
+         }
+         break;
 
-      return 1;
+       default:
+         nz_elts += mult;
+         if (!initializer_constant_valid_p (value, TREE_TYPE (value)))
+           nc_elts += mult;
+         break;
+       }
+    }
 
-    case CONSTRUCTOR:
-      if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
-       return CONSTRUCTOR_ELTS (exp) == NULL_TREE;
-      for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
-       if (! is_zeros_p (TREE_VALUE (elt)))
-         return 0;
+  *p_nz_elts += nz_elts;
+  *p_nc_elts += nc_elts;
+}
+
+void
+categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts,
+                         HOST_WIDE_INT *p_nc_elts)
+{
+  *p_nz_elts = 0;
+  *p_nc_elts = 0;
+  categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts);
+}
+
+/* Count the number of scalars in TYPE.  Return -1 on overflow or
+   variable-sized.  */
 
+HOST_WIDE_INT
+count_type_elements (tree type)
+{
+  const HOST_WIDE_INT max = ~((HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1));
+  switch (TREE_CODE (type))
+    {
+    case ARRAY_TYPE:
+      {
+       tree telts = array_type_nelts (type);
+       if (telts && host_integerp (telts, 1))
+         {
+           HOST_WIDE_INT n = tree_low_cst (telts, 1);
+           HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type));
+           if (n == 0)
+             return 0;
+           if (max / n < m)
+             return n * m;
+         }
+       return -1;
+      }
+
+    case RECORD_TYPE:
+      {
+       HOST_WIDE_INT n = 0, t;
+       tree f;
+
+       for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
+         if (TREE_CODE (f) == FIELD_DECL)
+           {
+             t = count_type_elements (TREE_TYPE (f));
+             if (t < 0)
+               return -1;
+             n += t;
+           }
+
+       return n;
+      }
+
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      {
+       /* Ho hum.  How in the world do we guess here?  Clearly it isn't
+          right to count the fields.  Guess based on the number of words.  */
+        HOST_WIDE_INT n = int_size_in_bytes (type);
+       if (n < 0)
+         return -1;
+       return n / UNITS_PER_WORD;
+      }
+
+    case COMPLEX_TYPE:
+      return 2;
+
+    case VECTOR_TYPE:
+      /* ??? This is broke.  We should encode the vector width in the tree.  */
+      return GET_MODE_NUNITS (TYPE_MODE (type));
+
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+    case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
+    case CHAR_TYPE:
+    case POINTER_TYPE:
+    case OFFSET_TYPE:
+    case REFERENCE_TYPE:
       return 1;
 
+    case VOID_TYPE:
+    case METHOD_TYPE:
+    case FILE_TYPE:
+    case SET_TYPE:
+    case FUNCTION_TYPE:
+    case LANG_TYPE:
     default:
-      return 0;
+      abort ();
     }
 }
 
@@ -4424,30 +4559,21 @@ int
 mostly_zeros_p (tree exp)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR)
+    
     {
-      int elts = 0, zeros = 0;
-      tree elt = CONSTRUCTOR_ELTS (exp);
+      HOST_WIDE_INT nz_elts, nc_elts, elts;
+
+      /* If there are no ranges of true bits, it is all zero.  */
       if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
-       {
-         /* If there are no ranges of true bits, it is all zero.  */
-         return elt == NULL_TREE;
-       }
-      for (; elt; elt = TREE_CHAIN (elt))
-       {
-         /* We do not handle the case where the index is a RANGE_EXPR,
-            so the statistic will be somewhat inaccurate.
-            We do make a more accurate count in store_constructor itself,
-            so since this function is only used for nested array elements,
-            this should be close enough.  */
-         if (mostly_zeros_p (TREE_VALUE (elt)))
-           zeros++;
-         elts++;
-       }
+       return CONSTRUCTOR_ELTS (exp) == NULL_TREE;
+
+      categorize_ctor_elements (exp, &nz_elts, &nc_elts);
+      elts = count_type_elements (TREE_TYPE (exp));
 
-      return 4 * zeros >= 3 * elts;
+      return nz_elts < elts / 4;
     }
 
-  return is_zeros_p (exp);
+  return initializer_zerop (exp);
 }
 \f
 /* Helper function for store_constructor.
@@ -4467,7 +4593,10 @@ store_constructor_field (rtx target, unsigned HOST_WIDE_INT bitsize,
                         tree exp, tree type, int cleared, int alias_set)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR
+      /* We can only call store_constructor recursively if the size and
+        bit position are on a byte boundary.  */
       && bitpos % BITS_PER_UNIT == 0
+      && (bitsize > 0 && bitsize % BITS_PER_UNIT == 0)
       /* If we have a nonzero bitpos for a register target, then we just
         let store_field do the bitfield handling.  This is unlikely to
         generate unnecessary clear instructions anyways.  */
@@ -4535,7 +4664,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
         set the initial value as zero so we can fold the value into
         a constant.  But if more than one register is involved,
         this probably loses.  */
-      else if (GET_CODE (target) == REG && TREE_STATIC (exp)
+      else if (REG_P (target) && TREE_STATIC (exp)
               && GET_MODE_SIZE (GET_MODE (target)) <= UNITS_PER_WORD)
        {
          emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
@@ -4547,9 +4676,10 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
         clear the whole structure first.  Don't do this if TARGET is a
         register whose mode size isn't equal to SIZE since clear_storage
         can't handle this case.  */
-      else if (((list_length (CONSTRUCTOR_ELTS (exp)) != fields_length (type))
-               || mostly_zeros_p (exp))
-              && (GET_CODE (target) != REG
+      else if (size > 0
+              && ((list_length (CONSTRUCTOR_ELTS (exp)) != fields_length (type))
+                  || mostly_zeros_p (exp))
+              && (!REG_P (target)
                   || ((HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (target))
                       == size)))
        {
@@ -4587,7 +4717,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
          if (field == 0)
            continue;
 
-         if (cleared && is_zeros_p (value))
+         if (cleared && initializer_zerop (value))
            continue;
 
          if (host_integerp (DECL_SIZE (field), 1))
@@ -4613,9 +4743,10 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            {
              rtx offset_rtx;
 
-             if (CONTAINS_PLACEHOLDER_P (offset))
-               offset = build (WITH_RECORD_EXPR, sizetype,
-                               offset, make_tree (TREE_TYPE (exp), target));
+             offset
+               = SUBSTITUTE_PLACEHOLDER_IN_EXPR (offset,
+                                                 make_tree (TREE_TYPE (exp),
+                                                            target));
 
              offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
              if (GET_CODE (to_rtx) != MEM)
@@ -4646,7 +4777,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
             start of a word, try to widen it to a full word.
             This special case allows us to output C++ member function
             initializations in a form that the optimizers can understand.  */
-         if (GET_CODE (target) == REG
+         if (REG_P (target)
              && bitsize < BITS_PER_WORD
              && bitpos % BITS_PER_WORD == 0
              && GET_MODE_CLASS (mode) == MODE_INT
@@ -4658,8 +4789,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
 
              if (TYPE_PRECISION (type) < BITS_PER_WORD)
                {
-                 type = (*lang_hooks.types.type_for_size)
-                   (BITS_PER_WORD, TREE_UNSIGNED (type));
+                 type = lang_hooks.types.type_for_size
+                   (BITS_PER_WORD, TYPE_UNSIGNED (type));
                  value = convert (type, value);
                }
 
@@ -4690,21 +4821,42 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
       tree elt;
       int i;
       int need_to_clear;
-      tree domain = TYPE_DOMAIN (type);
+      tree domain;
       tree elttype = TREE_TYPE (type);
       int const_bounds_p;
       HOST_WIDE_INT minelt = 0;
       HOST_WIDE_INT maxelt = 0;
+      int icode = 0;
+      rtx *vector = NULL;
+      int elt_size = 0;
+      unsigned n_elts = 0;
 
-      /* Vectors are like arrays, but the domain is stored via an array
-        type indirectly.  */
-      if (TREE_CODE (type) == VECTOR_TYPE)
+      if (TREE_CODE (type) == ARRAY_TYPE)
+       domain = TYPE_DOMAIN (type);
+      else
+       /* Vectors do not have domains; look up the domain of
+          the array embedded in the debug representation type.
+          FIXME Would probably be more efficient to treat vectors
+          separately from arrays.  */
        {
-         /* Note that although TYPE_DEBUG_REPRESENTATION_TYPE uses
-            the same field as TYPE_DOMAIN, we are not guaranteed that
-            it always will.  */
          domain = TYPE_DEBUG_REPRESENTATION_TYPE (type);
          domain = TYPE_DOMAIN (TREE_TYPE (TYPE_FIELDS (domain)));
+         if (REG_P (target) && VECTOR_MODE_P (GET_MODE (target)))
+           {
+             enum machine_mode mode = GET_MODE (target);
+
+             icode = (int) vec_init_optab->handlers[mode].insn_code;
+             if (icode != CODE_FOR_nothing)
+               {
+                 unsigned int i;
+
+                 elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
+                 n_elts = (GET_MODE_SIZE (mode) / elt_size);
+                 vector = alloca (n_elts);
+                 for (i = 0; i < n_elts; i++)
+                   vector [i] = CONST0_RTX (GET_MODE_INNER (mode));
+               }
+           }
        }
 
       const_bounds_p = (TYPE_MIN_VALUE (domain)
@@ -4722,7 +4874,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
       /* If the constructor has fewer elements than the array,
          clear the whole array first.  Similarly if this is
          static constructor of a non-BLKmode object.  */
-      if (cleared || (GET_CODE (target) == REG && TREE_STATIC (exp)))
+      if (cleared || (REG_P (target) && TREE_STATIC (exp)))
        need_to_clear = 1;
       else
        {
@@ -4769,7 +4921,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            need_to_clear = 1;
        }
 
-      if (need_to_clear && size > 0)
+      if (need_to_clear && size > 0 && !vector)
        {
          if (! cleared)
            {
@@ -4799,10 +4951,10 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
          tree index = TREE_PURPOSE (elt);
          rtx xtarget = target;
 
-         if (cleared && is_zeros_p (value))
+         if (cleared && initializer_zerop (value))
            continue;
 
-         unsignedp = TREE_UNSIGNED (elttype);
+         unsignedp = TYPE_UNSIGNED (elttype);
          mode = TYPE_MODE (elttype);
          if (mode == BLKmode)
            bitsize = (host_integerp (TYPE_SIZE (elttype), 1)
@@ -4815,11 +4967,13 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            {
              tree lo_index = TREE_OPERAND (index, 0);
              tree hi_index = TREE_OPERAND (index, 1);
-             rtx index_r, pos_rtx, loop_end;
-             struct nesting *loop;
+             rtx index_r, pos_rtx;
              HOST_WIDE_INT lo, hi, count;
              tree position;
 
+             if (vector)
+               abort ();
+
              /* If the range is constant and "small", unroll the loop.  */
              if (const_bounds_p
                  && host_integerp (lo_index, 0)
@@ -4854,10 +5008,12 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                }
              else
                {
-                 expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
-                 loop_end = gen_label_rtx ();
+                 rtx loop_start = gen_label_rtx ();
+                 rtx loop_end = gen_label_rtx ();
+                 tree exit_cond;
 
-                 unsignedp = TREE_UNSIGNED (domain);
+                 expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
+                 unsignedp = TYPE_UNSIGNED (domain);
 
                  index = build_decl (VAR_DECL, NULL_TREE, domain);
 
@@ -4874,7 +5030,11 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                      emit_queue ();
                    }
                  store_expr (lo_index, index_r, 0);
-                 loop = expand_start_loop (0);
+
+                 /* Build the head of the loop.  */
+                 do_pending_stack_adjust ();
+                 emit_queue ();
+                 emit_label (loop_start);
 
                  /* Assign value to element index.  */
                  position
@@ -4895,14 +5055,19 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                  else
                    store_expr (value, xtarget, 0);
 
-                 expand_exit_loop_if_false (loop,
-                                            build (LT_EXPR, integer_type_node,
-                                                   index, hi_index));
+                 /* Generate a conditional jump to exit the loop.  */
+                 exit_cond = build (LT_EXPR, integer_type_node,
+                                    index, hi_index);
+                 jumpif (exit_cond, loop_end);
 
+                 /* Update the loop counter, and jump to the head of
+                    the loop.  */
                  expand_increment (build (PREINCREMENT_EXPR,
                                           TREE_TYPE (index),
                                           index, integer_one_node), 0, 0);
-                 expand_end_loop ();
+                 emit_jump (loop_start);
+
+                 /* Build the end of the loop.  */
                  emit_label (loop_end);
                }
            }
@@ -4911,6 +5076,9 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            {
              tree position;
 
+             if (vector)
+               abort ();
+
              if (index == 0)
                index = ssize_int (1);
 
@@ -4928,6 +5096,16 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
              xtarget = adjust_address (xtarget, mode, 0);
              store_expr (value, xtarget, 0);
            }
+         else if (vector)
+           {
+             int pos;
+
+             if (index != 0)
+               pos = tree_low_cst (index, 0) - minelt;
+             else
+               pos = i;
+             vector[pos] = expand_expr (value, NULL_RTX, VOIDmode, 0);
+           }
          else
            {
              if (index != 0)
@@ -4943,12 +5121,16 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                  target = copy_rtx (target);
                  MEM_KEEP_ALIAS_SET_P (target) = 1;
                }
-
              store_constructor_field (target, bitsize, bitpos, mode, value,
                                       type, cleared, get_alias_set (elttype));
-
            }
        }
+      if (vector)
+       {
+         emit_insn (GEN_FCN (icode) (target,
+                                     gen_rtx_PARALLEL (GET_MODE (target),
+                                                       gen_rtvec_v (n_elts, vector))));
+       }
     }
 
   /* Set constructor assignments.  */
@@ -5015,7 +5197,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                {
                  if (word != 0 || ! cleared)
                    {
-                     rtx datum = GEN_INT (word);
+                     rtx datum = gen_int_mode (word, mode);
                      rtx to_rtx;
 
                      /* The assumption here is that it is safe to use
@@ -5085,7 +5267,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            {
              targetx
                = assign_temp
-                 ((build_qualified_type ((*lang_hooks.types.type_for_mode)
+                 ((build_qualified_type (lang_hooks.types.type_for_mode
                                          (GET_MODE (target), 0),
                                          TYPE_QUAL_CONST)),
                   0, 1, 1);
@@ -5178,7 +5360,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
      twice, once with emit_move_insn and once via store_field.  */
 
   if (mode == BLKmode
-      && (GET_CODE (target) == REG || GET_CODE (target) == SUBREG))
+      && (REG_P (target) || GET_CODE (target) == SUBREG))
     {
       rtx object = assign_temp (type, 0, 1, 1);
       rtx blk_object = adjust_address (object, BLKmode, 0);
@@ -5201,7 +5383,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
 
       if (bitpos != 0)
        abort ();
-      return store_expr (exp, target, 0);
+      return store_expr (exp, target, value_mode != VOIDmode);
     }
 
   /* If the structure is in a register or if the component
@@ -5212,7 +5394,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
       || (mode != BLKmode && ! direct_store[(int) mode]
          && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
          && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
-      || GET_CODE (target) == REG
+      || REG_P (target)
       || GET_CODE (target) == SUBREG
       /* If the field isn't aligned enough to store as an ordinary memref,
         store it as a bit field.  */
@@ -5308,7 +5490,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
       /* If a value is wanted, it must be the lhs;
         so make the address stable for multiple use.  */
 
-      if (value_mode != VOIDmode && GET_CODE (addr) != REG
+      if (value_mode != VOIDmode && !REG_P (addr)
          && ! CONSTANT_ADDRESS_P (addr)
          /* A frame-pointer reference is already stable.  */
          && ! (GET_CODE (addr) == PLUS
@@ -5364,7 +5546,6 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
   enum machine_mode mode = VOIDmode;
   tree offset = size_zero_node;
   tree bit_offset = bitsize_zero_node;
-  tree placeholder_ptr = 0;
   tree tem;
 
   /* First get the mode, signedness, and size.  We do this from just the
@@ -5375,17 +5556,17 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
       if (! DECL_BIT_FIELD (TREE_OPERAND (exp, 1)))
        mode = DECL_MODE (TREE_OPERAND (exp, 1));
 
-      *punsignedp = TREE_UNSIGNED (TREE_OPERAND (exp, 1));
+      *punsignedp = DECL_UNSIGNED (TREE_OPERAND (exp, 1));
     }
   else if (TREE_CODE (exp) == BIT_FIELD_REF)
     {
       size_tree = TREE_OPERAND (exp, 1);
-      *punsignedp = TREE_UNSIGNED (exp);
+      *punsignedp = BIT_FIELD_REF_UNSIGNED (exp);
     }
   else
     {
       mode = TYPE_MODE (TREE_TYPE (exp));
-      *punsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
+      *punsignedp = TYPE_UNSIGNED (TREE_TYPE (exp));
 
       if (mode == BLKmode)
        size_tree = TYPE_SIZE (TREE_TYPE (exp));
@@ -5410,15 +5591,13 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
       else if (TREE_CODE (exp) == COMPONENT_REF)
        {
          tree field = TREE_OPERAND (exp, 1);
-         tree this_offset = DECL_FIELD_OFFSET (field);
+         tree this_offset = component_ref_field_offset (exp);
 
          /* If this field hasn't been filled in yet, don't go
             past it.  This should only happen when folding expressions
             made during type construction.  */
          if (this_offset == 0)
            break;
-         else if (CONTAINS_PLACEHOLDER_P (this_offset))
-           this_offset = build (WITH_RECORD_EXPR, sizetype, this_offset, exp);
 
          offset = size_binop (PLUS_EXPR, offset, this_offset);
          bit_offset = size_binop (PLUS_EXPR, bit_offset,
@@ -5431,48 +5610,23 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
               || TREE_CODE (exp) == ARRAY_RANGE_REF)
        {
          tree index = TREE_OPERAND (exp, 1);
-         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 (TREE_TYPE (array)));
+         tree low_bound = array_ref_low_bound (exp);
+         tree unit_size = array_ref_element_size (exp);
 
          /* 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
             index, then convert to sizetype and multiply by the size of the
             array element.  */
-         if (low_bound != 0 && ! integer_zerop (low_bound))
+         if (! integer_zerop (low_bound))
            index = fold (build (MINUS_EXPR, TREE_TYPE (index),
                                 index, low_bound));
 
-         /* If the index has a self-referential type, pass it to a
-            WITH_RECORD_EXPR; if the component size is, pass our
-            component to one.  */
-         if (CONTAINS_PLACEHOLDER_P (index))
-           index = build (WITH_RECORD_EXPR, TREE_TYPE (index), index, exp);
-         if (CONTAINS_PLACEHOLDER_P (unit_size))
-           unit_size = build (WITH_RECORD_EXPR, sizetype, unit_size, array);
-
          offset = size_binop (PLUS_EXPR, offset,
                               size_binop (MULT_EXPR,
                                           convert (sizetype, index),
                                           unit_size));
        }
 
-      else if (TREE_CODE (exp) == PLACEHOLDER_EXPR)
-       {
-         tree new = find_placeholder (exp, &placeholder_ptr);
-
-         /* If we couldn't find the replacement, return the PLACEHOLDER_EXPR.
-            We might have been called from tree optimization where we
-            haven't set up an object yet.  */
-         if (new == 0)
-           break;
-         else
-           exp = new;
-
-         continue;
-       }
-
       /* We can go inside most conversions: all NON_VALUE_EXPRs, all normal
         conversions that don't change the mode, and all view conversions
         except those that need to "step up" the alignment.  */
@@ -5514,6 +5668,70 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
   return exp;
 }
 
+/* Return a tree of sizetype representing the size, in bytes, of the element
+   of EXP, an ARRAY_REF.  */
+
+tree
+array_ref_element_size (tree exp)
+{
+  tree aligned_size = TREE_OPERAND (exp, 3);
+  tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+  /* If a size was specified in the ARRAY_REF, it's the size measured
+     in alignment units of the element type.  So multiply by that value.  */
+  if (aligned_size)
+    return size_binop (MULT_EXPR, aligned_size,
+                      size_int (TYPE_ALIGN (elmt_type) / BITS_PER_UNIT));
+
+  /* Otherwise, take the size from that of the element type.  Substitute 
+     any PLACEHOLDER_EXPR that we have.  */
+  else
+    return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_SIZE_UNIT (elmt_type), exp);
+}
+
+/* Return a tree representing the lower bound of the array mentioned in
+   EXP, an ARRAY_REF.  */
+
+tree
+array_ref_low_bound (tree exp)
+{
+  tree domain_type = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+  /* If a lower bound is specified in EXP, use it.  */
+  if (TREE_OPERAND (exp, 2))
+    return TREE_OPERAND (exp, 2);
+
+  /* Otherwise, if there is a domain type and it has a lower bound, use it,
+     substituting for a PLACEHOLDER_EXPR as needed.  */
+  if (domain_type && TYPE_MIN_VALUE (domain_type))
+    return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_MIN_VALUE (domain_type), exp);
+
+  /* Otherwise, return a zero of the appropriate type.  */
+  return fold_convert (TREE_TYPE (TREE_OPERAND (exp, 1)), integer_zero_node);
+}
+
+/* Return a tree representing the offset, in bytes, of the field referenced
+   by EXP.  This does not include any offset in DECL_FIELD_BIT_OFFSET.  */
+
+tree
+component_ref_field_offset (tree exp)
+{
+  tree aligned_offset = TREE_OPERAND (exp, 2);
+  tree field = TREE_OPERAND (exp, 1);
+
+  /* If an offset was specified in the COMPONENT_REF, it's the offset measured
+     in units of DECL_OFFSET_ALIGN / BITS_PER_UNIT.  So multiply by that
+     value.  */
+  if (aligned_offset)
+    return size_binop (MULT_EXPR, aligned_offset,
+                      size_int (DECL_OFFSET_ALIGN (field) / BITS_PER_UNIT));
+
+  /* Otherwise, take the offset from that of the field.  Substitute 
+     any PLACEHOLDER_EXPR that we have.  */
+  else
+    return SUBSTITUTE_PLACEHOLDER_IN_EXPR (DECL_FIELD_OFFSET (field), exp);
+}
+
 /* Return 1 if T is an expression that get_inner_reference handles.  */
 
 int
@@ -5557,6 +5775,20 @@ force_operand (rtx value, rtx target)
   rtx subtarget = get_subtarget (target);
   enum rtx_code code = GET_CODE (value);
 
+  /* Check for subreg applied to an expression produced by loop optimizer.  */
+  if (code == SUBREG
+      && !REG_P (SUBREG_REG (value))
+      && GET_CODE (SUBREG_REG (value)) != MEM)
+    {
+      value = simplify_gen_subreg (GET_MODE (value),
+                                  force_reg (GET_MODE (SUBREG_REG (value)),
+                                             force_operand (SUBREG_REG (value),
+                                                            NULL_RTX)),
+                                  GET_MODE (SUBREG_REG (value)),
+                                  SUBREG_BYTE (value));
+      code = GET_CODE (value);
+    }
+
   /* Check for a PIC address load.  */
   if ((code == PLUS || code == MINUS)
       && XEXP (value, 0) == pic_offset_table_rtx
@@ -5579,10 +5811,10 @@ force_operand (rtx value, rtx target)
       return target;
     }
 
-  if (GET_RTX_CLASS (code) == '2' || GET_RTX_CLASS (code) == 'c')
+  if (ARITHMETIC_P (value))
     {
       op2 = XEXP (value, 1);
-      if (!CONSTANT_P (op2) && !(GET_CODE (op2) == REG && op2 != subtarget))
+      if (!CONSTANT_P (op2) && !(REG_P (op2) && op2 != subtarget))
        subtarget = 0;
       if (code == MINUS && GET_CODE (op2) == CONST_INT)
        {
@@ -5598,7 +5830,7 @@ force_operand (rtx value, rtx target)
          creating another one around this addition.  */
       if (code == PLUS && GET_CODE (op2) == CONST_INT
          && GET_CODE (XEXP (value, 0)) == PLUS
-         && GET_CODE (XEXP (XEXP (value, 0), 0)) == REG
+         && REG_P (XEXP (XEXP (value, 0), 0))
          && REGNO (XEXP (XEXP (value, 0), 0)) >= FIRST_VIRTUAL_REGISTER
          && REGNO (XEXP (XEXP (value, 0), 0)) <= LAST_VIRTUAL_REGISTER)
        {
@@ -5648,7 +5880,7 @@ force_operand (rtx value, rtx target)
                                      target, 1, OPTAB_LIB_WIDEN);
        }
     }
-  if (GET_RTX_CLASS (code) == '1')
+  if (UNARY_P (value))
     {
       op1 = force_operand (XEXP (value, 0), NULL_RTX);
       return expand_simple_unop (GET_MODE (value), code, op1, target, 0);
@@ -5713,7 +5945,7 @@ safe_from_p (rtx x, tree exp, int top_p)
   if (GET_CODE (x) == SUBREG)
     {
       x = SUBREG_REG (x);
-      if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
+      if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
        return 0;
     }
 
@@ -5774,7 +6006,7 @@ safe_from_p (rtx x, tree exp, int top_p)
     case '<':
       if (!safe_from_p (x, TREE_OPERAND (exp, 1), 0))
        return 0;
-      /* FALLTHRU */
+      /* Fall through.  */
 
     case '1':
       return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
@@ -5820,7 +6052,7 @@ safe_from_p (rtx x, tree exp, int top_p)
        case CALL_EXPR:
          /* Assume that the call will clobber all hard registers and
             all of memory.  */
-         if ((GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
+         if ((REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
              || GET_CODE (x) == MEM)
            return 0;
          break;
@@ -5886,7 +6118,7 @@ safe_from_p (rtx x, tree exp, int top_p)
         special handling.  */
       if ((unsigned int) TREE_CODE (exp)
          >= (unsigned int) LAST_AND_UNUSED_TREE_CODE
-         && !(*lang_hooks.safe_from_p) (x, exp))
+         && !lang_hooks.safe_from_p (x, exp))
        return 0;
     }
 
@@ -5897,7 +6129,7 @@ safe_from_p (rtx x, tree exp, int top_p)
       if (GET_CODE (exp_rtl) == SUBREG)
        {
          exp_rtl = SUBREG_REG (exp_rtl);
-         if (GET_CODE (exp_rtl) == REG
+         if (REG_P (exp_rtl)
              && REGNO (exp_rtl) < FIRST_PSEUDO_REGISTER)
            return 0;
        }
@@ -5930,60 +6162,6 @@ var_rtx (tree exp)
       return 0;
     }
 }
-
-#ifdef MAX_INTEGER_COMPUTATION_MODE
-
-void
-check_max_integer_computation_mode (tree exp)
-{
-  enum tree_code code;
-  enum machine_mode mode;
-
-  /* Strip any NOPs that don't change the mode.  */
-  STRIP_NOPS (exp);
-  code = TREE_CODE (exp);
-
-  /* We must allow conversions of constants to MAX_INTEGER_COMPUTATION_MODE.  */
-  if (code == NOP_EXPR
-      && TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST)
-    return;
-
-  /* First check the type of the overall operation.   We need only look at
-     unary, binary and relational operations.  */
-  if (TREE_CODE_CLASS (code) == '1'
-      || TREE_CODE_CLASS (code) == '2'
-      || TREE_CODE_CLASS (code) == '<')
-    {
-      mode = TYPE_MODE (TREE_TYPE (exp));
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && mode > MAX_INTEGER_COMPUTATION_MODE)
-       internal_error ("unsupported wide integer operation");
-    }
-
-  /* Check operand of a unary op.  */
-  if (TREE_CODE_CLASS (code) == '1')
-    {
-      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && mode > MAX_INTEGER_COMPUTATION_MODE)
-       internal_error ("unsupported wide integer operation");
-    }
-
-  /* Check operands of a binary/comparison op.  */
-  if (TREE_CODE_CLASS (code) == '2' || TREE_CODE_CLASS (code) == '<')
-    {
-      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && mode > MAX_INTEGER_COMPUTATION_MODE)
-       internal_error ("unsupported wide integer operation");
-
-      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1)));
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && mode > MAX_INTEGER_COMPUTATION_MODE)
-       internal_error ("unsupported wide integer operation");
-    }
-}
-#endif
 \f
 /* Return the highest power of two that EXP is known to be a multiple of.
    This is used in updating alignment of MEMs in array references.  */
@@ -6036,7 +6214,7 @@ highest_pow2_factor (tree exp)
       break;
 
     case NON_LVALUE_EXPR:  case NOP_EXPR:  case CONVERT_EXPR:
-    case SAVE_EXPR: case WITH_RECORD_EXPR:
+    case SAVE_EXPR:
       return highest_pow2_factor (TREE_OPERAND (exp, 0));
 
     case COMPOUND_EXPR:
@@ -6054,81 +6232,86 @@ highest_pow2_factor (tree exp)
   return 1;
 }
 
-/* Similar, except that it is known that the expression must be a multiple
-   of the alignment of TYPE.  */
+/* Similar, except that the alignment requirements of TARGET are
+   taken into account.  Assume it is at least as aligned as its
+   type, unless it is a COMPONENT_REF in which case the layout of
+   the structure gives the alignment.  */
 
 static unsigned HOST_WIDE_INT
-highest_pow2_factor_for_type (tree type, tree exp)
+highest_pow2_factor_for_target (tree target, tree exp)
 {
-  unsigned HOST_WIDE_INT type_align, factor;
+  unsigned HOST_WIDE_INT target_align, factor;
 
   factor = highest_pow2_factor (exp);
-  type_align = TYPE_ALIGN (type) / BITS_PER_UNIT;
-  return MAX (factor, type_align);
+  if (TREE_CODE (target) == COMPONENT_REF)
+    target_align = DECL_ALIGN (TREE_OPERAND (target, 1)) / BITS_PER_UNIT;
+  else
+    target_align = TYPE_ALIGN (TREE_TYPE (target)) / BITS_PER_UNIT;
+  return MAX (factor, target_align);
 }
 \f
-/* Return an object on the placeholder list that matches EXP, a
-   PLACEHOLDER_EXPR.  An object "matches" if it is of the type of the
-   PLACEHOLDER_EXPR or a pointer type to it.  For further information, see
-   tree.def.  If no such object is found, return 0.  If PLIST is nonzero, it
-   is a location which initially points to a starting location in the
-   placeholder list (zero means start of the list) and where a pointer into
-   the placeholder list at which the object is found is placed.  */
+/* Expands variable VAR.  */
 
-tree
-find_placeholder (tree exp, tree *plist)
+void
+expand_var (tree var)
 {
-  tree type = TREE_TYPE (exp);
-  tree placeholder_expr;
+  if (DECL_EXTERNAL (var))
+    return;
 
-  for (placeholder_expr
-       = plist && *plist ? TREE_CHAIN (*plist) : placeholder_list;
-       placeholder_expr != 0;
-       placeholder_expr = TREE_CHAIN (placeholder_expr))
-    {
-      tree need_type = TYPE_MAIN_VARIANT (type);
-      tree elt;
+  if (TREE_STATIC (var))
+    /* If this is an inlined copy of a static local variable,
+       look up the original decl.  */
+    var = DECL_ORIGIN (var);
 
-      /* Find the outermost reference that is of the type we want.  If none,
-        see if any object has a type that is a pointer to the type we
-        want.  */
-      for (elt = TREE_PURPOSE (placeholder_expr); elt != 0;
-          elt = ((TREE_CODE (elt) == COMPOUND_EXPR
-                  || TREE_CODE (elt) == COND_EXPR)
-                 ? TREE_OPERAND (elt, 1)
-                 : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
-                    || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
-                    || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
-                    || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
-                 ? TREE_OPERAND (elt, 0) : 0))
-       if (TYPE_MAIN_VARIANT (TREE_TYPE (elt)) == need_type)
-         {
-           if (plist)
-             *plist = placeholder_expr;
-           return elt;
-         }
+  if (TREE_STATIC (var)
+      ? !TREE_ASM_WRITTEN (var)
+      : !DECL_RTL_SET_P (var))
+    {
+      if (TREE_CODE (var) == VAR_DECL && DECL_DEFER_OUTPUT (var))
+       {
+         /* Prepare a mem & address for the decl.  */
+         rtx x;
+                   
+         if (TREE_STATIC (var))
+           abort ();
 
-      for (elt = TREE_PURPOSE (placeholder_expr); elt != 0;
-          elt
-          = ((TREE_CODE (elt) == COMPOUND_EXPR
-              || TREE_CODE (elt) == COND_EXPR)
-             ? TREE_OPERAND (elt, 1)
-             : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
-                || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
-                || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
-                || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
-             ? TREE_OPERAND (elt, 0) : 0))
-       if (POINTER_TYPE_P (TREE_TYPE (elt))
-           && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (elt)))
-               == need_type))
-         {
-           if (plist)
-             *plist = placeholder_expr;
-           return build1 (INDIRECT_REF, need_type, elt);
-         }
+         x = gen_rtx_MEM (DECL_MODE (var),
+                          gen_reg_rtx (Pmode));
+
+         set_mem_attributes (x, var, 1);
+         SET_DECL_RTL (var, x);
+       }
+      else if (lang_hooks.expand_decl (var))
+       /* OK.  */;
+      else if (TREE_CODE (var) == VAR_DECL && !TREE_STATIC (var))
+       expand_decl (var);
+      else if (TREE_CODE (var) == VAR_DECL && TREE_STATIC (var))
+       rest_of_decl_compilation (var, NULL, 0, 0);
+      else if (TREE_CODE (var) == TYPE_DECL
+              || TREE_CODE (var) == CONST_DECL
+              || TREE_CODE (var) == FUNCTION_DECL
+              || TREE_CODE (var) == LABEL_DECL)
+       /* No expansion needed.  */;
+      else
+       abort ();
     }
+}
 
-  return 0;
+/* Expands declarations of variables in list VARS.  */
+
+static void
+expand_vars (tree vars)
+{
+  for (; vars; vars = TREE_CHAIN (vars))
+    {
+      tree var = vars;
+
+      if (DECL_EXTERNAL (var))
+       continue;
+
+      expand_var (var);
+      expand_decl_init (var);
+    }
 }
 
 /* Subroutine of expand_expr.  Expand the two operands of a binary
@@ -6199,15 +6382,99 @@ expand_operands (tree exp0, tree exp1, rtx target, rtx *op0, rtx *op1,
    marked TARGET so that it's safe from being trashed by libcalls.  We
    don't want to use TARGET for anything but the final result;
    Intermediate values must go elsewhere.   Additionally, calls to
-   emit_block_move will be flagged with BLOCK_OP_CALL_PARM.  */
+   emit_block_move will be flagged with BLOCK_OP_CALL_PARM.  
+
+   If EXP is a VAR_DECL whose DECL_RTL was a MEM with an invalid
+   address, and ALT_RTL is non-NULL, then *ALT_RTL is set to the
+   DECL_RTL of the VAR_DECL.  *ALT_RTL is also set if EXP is a
+   COMPOUND_EXPR whose second argument is such a VAR_DECL, and so on
+   recursively.  */
+
+static rtx expand_expr_real_1 (tree, rtx, enum machine_mode,
+                              enum expand_modifier, rtx *);
 
 rtx
-expand_expr (tree exp, rtx target, enum machine_mode tmode,
-            enum expand_modifier modifier)
+expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
+                 enum expand_modifier modifier, rtx *alt_rtl)
+{
+  int rn = -1;
+  rtx ret, last = NULL;
+
+  /* Handle ERROR_MARK before anybody tries to access its type.  */
+  if (TREE_CODE (exp) == ERROR_MARK
+      || TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK)
+    {
+      ret = CONST0_RTX (tmode);
+      return ret ? ret : const0_rtx;
+    }
+
+  if (flag_non_call_exceptions)
+    {
+      rn = lookup_stmt_eh_region (exp);
+      /* If rn < 0, then either (1) tree-ssa not used or (2) doesn't throw.  */
+      if (rn >= 0)
+       last = get_last_insn ();
+    }
+
+  /* If this is an expression of some kind and it has an associated line
+     number, then emit the line number before expanding the expression. 
+
+     We need to save and restore the file and line information so that
+     errors discovered during expansion are emitted with the right
+     information.  It would be better of the diagnostic routines 
+     used the file/line information embedded in the tree nodes rather
+     than globals.  */
+  if (cfun && EXPR_HAS_LOCATION (exp))
+    {
+      location_t saved_location = input_location;
+      input_location = EXPR_LOCATION (exp);
+      emit_line_note (input_location);
+      
+      /* Record where the insns produced belong.  */
+      if (cfun->dont_emit_block_notes)
+       record_block_change (TREE_BLOCK (exp));
+
+      ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl);
+
+      input_location = saved_location;
+    }
+  else
+    {
+      ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl);
+    }
+
+  /* If using non-call exceptions, mark all insns that may trap.
+     expand_call() will mark CALL_INSNs before we get to this code,
+     but it doesn't handle libcalls, and these may trap.  */
+  if (rn >= 0)
+    {  
+      rtx insn;
+      for (insn = next_real_insn (last); insn; 
+          insn = next_real_insn (insn))
+       {
+         if (! find_reg_note (insn, REG_EH_REGION, NULL_RTX)
+             /* If we want exceptions for non-call insns, any
+                may_trap_p instruction may throw.  */
+             && GET_CODE (PATTERN (insn)) != CLOBBER
+             && GET_CODE (PATTERN (insn)) != USE
+             && (GET_CODE (insn) == CALL_INSN || may_trap_p (PATTERN (insn))))
+           {
+             REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION, GEN_INT (rn),
+                                                 REG_NOTES (insn));
+           }
+       }
+    }
+
+  return ret;
+}
+
+static rtx
+expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
+                   enum expand_modifier modifier, rtx *alt_rtl)
 {
   rtx op0, op1, temp;
   tree type = TREE_TYPE (exp);
-  int unsignedp = TREE_UNSIGNED (type);
+  int unsignedp;
   enum machine_mode mode;
   enum tree_code code = TREE_CODE (exp);
   optab this_optab;
@@ -6215,16 +6482,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
   int ignore;
   tree context;
 
-  /* Handle ERROR_MARK before anybody tries to access its type.  */
-  if (TREE_CODE (exp) == ERROR_MARK || TREE_CODE (type) == ERROR_MARK)
-    {
-      op0 = CONST0_RTX (tmode);
-      if (op0 != 0)
-       return op0;
-      return const0_rtx;
-    }
-
   mode = TYPE_MODE (type);
+  unsignedp = TYPE_UNSIGNED (type);
+
   /* Use subtarget as the target for operand 0 of a binary operation.  */
   subtarget = get_subtarget (target);
   original_target = target;
@@ -6287,49 +6547,6 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
       target = 0;
     }
 
-#ifdef MAX_INTEGER_COMPUTATION_MODE
-  /* Only check stuff here if the mode we want is different from the mode
-     of the expression; if it's the same, check_max_integer_computation_mode
-     will handle it.  Do we really need to check this stuff at all?  */
-
-  if (target
-      && GET_MODE (target) != mode
-      && TREE_CODE (exp) != INTEGER_CST
-      && TREE_CODE (exp) != PARM_DECL
-      && TREE_CODE (exp) != ARRAY_REF
-      && TREE_CODE (exp) != ARRAY_RANGE_REF
-      && TREE_CODE (exp) != COMPONENT_REF
-      && TREE_CODE (exp) != BIT_FIELD_REF
-      && TREE_CODE (exp) != INDIRECT_REF
-      && TREE_CODE (exp) != CALL_EXPR
-      && TREE_CODE (exp) != VAR_DECL
-      && TREE_CODE (exp) != RTL_EXPR)
-    {
-      enum machine_mode mode = GET_MODE (target);
-
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && mode > MAX_INTEGER_COMPUTATION_MODE)
-       internal_error ("unsupported wide integer operation");
-    }
-
-  if (tmode != mode
-      && TREE_CODE (exp) != INTEGER_CST
-      && TREE_CODE (exp) != PARM_DECL
-      && TREE_CODE (exp) != ARRAY_REF
-      && TREE_CODE (exp) != ARRAY_RANGE_REF
-      && TREE_CODE (exp) != COMPONENT_REF
-      && TREE_CODE (exp) != BIT_FIELD_REF
-      && TREE_CODE (exp) != INDIRECT_REF
-      && TREE_CODE (exp) != VAR_DECL
-      && TREE_CODE (exp) != CALL_EXPR
-      && TREE_CODE (exp) != RTL_EXPR
-      && GET_MODE_CLASS (tmode) == MODE_INT
-      && tmode > MAX_INTEGER_COMPUTATION_MODE)
-    internal_error ("unsupported wide integer operation");
-
-  check_max_integer_computation_mode (exp);
-#endif
-
   /* If will do cse, generate all results into pseudo registers
      since 1) that allows cse to find more things
      and 2) otherwise cse could produce an insn the machine
@@ -6338,7 +6555,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
      Another is a CALL_EXPR which must return in memory.  */
 
   if (! cse_not_expected && mode != BLKmode && target
-      && (GET_CODE (target) != REG || REGNO (target) < FIRST_PSEUDO_REGISTER)
+      && (!REG_P (target) || REGNO (target) < FIRST_PSEUDO_REGISTER)
       && ! (code == CONSTRUCTOR && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
       && ! (code == CALL_EXPR && aggregate_value_p (exp, exp)))
     target = 0;
@@ -6348,20 +6565,15 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
     case LABEL_DECL:
       {
        tree function = decl_function_context (exp);
-       /* Labels in containing functions, or labels used from initializers,
-          must be forced.  */
-       if (modifier == EXPAND_INITIALIZER
-           || (function != current_function_decl
-               && function != inline_function_decl
-               && function != 0))
-         temp = force_label_rtx (exp);
-       else
-         temp = label_rtx (exp);
 
-       temp = gen_rtx_MEM (FUNCTION_MODE, gen_rtx_LABEL_REF (Pmode, temp));
+       temp = label_rtx (exp);
+       temp = gen_rtx_LABEL_REF (Pmode, temp);
+
        if (function != current_function_decl
-           && function != inline_function_decl && function != 0)
-         LABEL_REF_NONLOCAL_P (XEXP (temp, 0)) = 1;
+           && function != 0)
+         LABEL_REF_NONLOCAL_P (temp) = 1;
+
+       temp = gen_rtx_MEM (FUNCTION_MODE, temp);
        return temp;
       }
 
@@ -6404,13 +6616,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
       /* Handle variables inherited from containing functions.  */
       context = decl_function_context (exp);
 
-      /* We treat inline_function_decl as an alias for the current function
-        because that is the inline function whose vars, types, etc.
-        are being merged into the current function.
-        See expand_inline_function.  */
-
       if (context != 0 && context != current_function_decl
-         && context != inline_function_decl
          /* If var is static, we don't need a static chain to access it.  */
          && ! (GET_CODE (DECL_RTL (exp)) == MEM
                && CONSTANT_P (XEXP (DECL_RTL (exp), 0))))
@@ -6421,7 +6627,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
          DECL_NONLOCAL (exp) = 1;
          if (DECL_NO_STATIC_CHAIN (current_function_decl))
            abort ();
-         (*lang_hooks.mark_addressable) (exp);
+         lang_hooks.mark_addressable (exp);
          if (GET_CODE (DECL_RTL (exp)) != MEM)
            abort ();
          addr = XEXP (DECL_RTL (exp), 0);
@@ -6440,7 +6646,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
         See expand_decl.  */
 
       else if (GET_CODE (DECL_RTL (exp)) == MEM
-              && GET_CODE (XEXP (DECL_RTL (exp), 0)) == REG)
+              && REG_P (XEXP (DECL_RTL (exp), 0)))
        temp = validize_mem (DECL_RTL (exp));
 
       /* If DECL_RTL is memory, we are in the normal case and either
@@ -6454,15 +6660,19 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
               && (! memory_address_p (DECL_MODE (exp),
                                       XEXP (DECL_RTL (exp), 0))
                   || (flag_force_addr
-                      && GET_CODE (XEXP (DECL_RTL (exp), 0)) != REG)))
-       temp = replace_equiv_address (DECL_RTL (exp),
-                                     copy_rtx (XEXP (DECL_RTL (exp), 0)));
+                      && !REG_P (XEXP (DECL_RTL (exp), 0)))))
+       {
+         if (alt_rtl)
+           *alt_rtl = DECL_RTL (exp);
+         temp = replace_equiv_address (DECL_RTL (exp),
+                                       copy_rtx (XEXP (DECL_RTL (exp), 0)));
+       }
 
       /* If we got something, return it.  But first, set the alignment
         if the address is a register.  */
       if (temp != 0)
        {
-         if (GET_CODE (temp) == MEM && GET_CODE (XEXP (temp, 0)) == REG)
+         if (GET_CODE (temp) == MEM && REG_P (XEXP (temp, 0)))
            mark_reg_pointer (XEXP (temp, 0), DECL_ALIGN (exp));
 
          return temp;
@@ -6472,7 +6682,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
         must be a promoted value.  We return a SUBREG of the wanted mode,
         but mark it so that we know that it was already extended.  */
 
-      if (GET_CODE (DECL_RTL (exp)) == REG
+      if (REG_P (DECL_RTL (exp))
          && GET_MODE (DECL_RTL (exp)) != DECL_MODE (exp))
        {
          /* Get the signedness used for this variable.  Ensure we get the
@@ -6564,29 +6774,6 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
                                      copy_rtx (XEXP (temp, 0)));
       return temp;
 
-    case EXPR_WITH_FILE_LOCATION:
-      {
-       rtx to_return;
-       struct file_stack fs;
-
-       fs.location = input_location;
-       fs.next = expr_wfl_stack;
-       input_filename = EXPR_WFL_FILENAME (exp);
-       input_line = EXPR_WFL_LINENO (exp);
-       expr_wfl_stack = &fs;
-       if (EXPR_WFL_EMIT_LINE_NOTE (exp))
-         emit_line_note (input_location);
-       /* Possibly avoid switching back and forth here.  */
-       to_return = expand_expr (EXPR_WFL_NODE (exp),
-                                (ignore ? const0_rtx : target),
-                                tmode, modifier);
-       if (expr_wfl_stack != &fs)
-         abort ();
-       input_location = fs.location;
-       expr_wfl_stack = fs.next;
-       return to_return;
-      }
-
     case SAVE_EXPR:
       context = decl_function_context (exp);
 
@@ -6595,11 +6782,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
       if (context == 0)
        SAVE_EXPR_CONTEXT (exp) = current_function_decl;
 
-      /* We treat inline_function_decl as an alias for the current function
-        because that is the inline function whose vars, types, etc.
-        are being merged into the current function.
-        See expand_inline_function.  */
-      if (context == current_function_decl || context == inline_function_decl)
+      if (context == current_function_decl)
        context = 0;
 
       /* If this is non-local, handle it.  */
@@ -6610,7 +6793,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
          find_function_data (context);
 
          temp = SAVE_EXPR_RTL (exp);
-         if (temp && GET_CODE (temp) == REG)
+         if (temp && REG_P (temp))
            {
              put_var_into_stack (exp, /*rescan=*/true);
              temp = SAVE_EXPR_RTL (exp);
@@ -6632,7 +6815,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
                                3, 0, 0);
 
          SAVE_EXPR_RTL (exp) = temp;
-         if (!optimize && GET_CODE (temp) == REG)
+         if (!optimize && REG_P (temp))
            save_expr_regs = gen_rtx_EXPR_LIST (VOIDmode, temp,
                                                save_expr_regs);
 
@@ -6641,7 +6824,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
             wanted mode but mark it so that we know that it was already
             extended.  */
 
-         if (GET_CODE (temp) == REG && GET_MODE (temp) != mode)
+         if (REG_P (temp) && GET_MODE (temp) != mode)
            {
              temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
              promote_mode (type, mode, &unsignedp, 0);
@@ -6662,7 +6845,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
         must be a promoted value.  We return a SUBREG of the wanted mode,
         but mark it so that we know that it was already extended.  */
 
-      if (GET_CODE (SAVE_EXPR_RTL (exp)) == REG
+      if (REG_P (SAVE_EXPR_RTL (exp))
          && GET_MODE (SAVE_EXPR_RTL (exp)) != mode)
        {
          /* Compute the signedness and make the proper SUBREG.  */
@@ -6680,35 +6863,10 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
        rtx temp;
        temp = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
        TREE_OPERAND (exp, 0)
-         = (*lang_hooks.unsave_expr_now) (TREE_OPERAND (exp, 0));
+         = lang_hooks.unsave_expr_now (TREE_OPERAND (exp, 0));
        return temp;
       }
 
-    case PLACEHOLDER_EXPR:
-      {
-       tree old_list = placeholder_list;
-       tree placeholder_expr = 0;
-
-       exp = find_placeholder (exp, &placeholder_expr);
-       if (exp == 0)
-         abort ();
-
-       placeholder_list = TREE_CHAIN (placeholder_expr);
-       temp = expand_expr (exp, original_target, tmode, modifier);
-       placeholder_list = old_list;
-       return temp;
-      }
-
-    case WITH_RECORD_EXPR:
-      /* Put the object on the placeholder list, expand our first operand,
-        and pop the list.  */
-      placeholder_list = tree_cons (TREE_OPERAND (exp, 1), NULL_TREE,
-                                   placeholder_list);
-      target = expand_expr (TREE_OPERAND (exp, 0), original_target, tmode,
-                           modifier);
-      placeholder_list = TREE_CHAIN (placeholder_list);
-      return target;
-
     case GOTO_EXPR:
       if (TREE_CODE (TREE_OPERAND (exp, 0)) == LABEL_DECL)
        expand_goto (TREE_OPERAND (exp, 0));
@@ -6716,10 +6874,11 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
        expand_computed_goto (TREE_OPERAND (exp, 0));
       return const0_rtx;
 
+    /* These are lowered during gimplification, so we should never ever
+       see them here.  */
+    case LOOP_EXPR:
     case EXIT_EXPR:
-      expand_exit_loop_if_false (NULL,
-                                invert_truthvalue (TREE_OPERAND (exp, 0)));
-      return const0_rtx;
+      abort ();
 
     case LABELED_BLOCK_EXPR:
       if (LABELED_BLOCK_BODY (exp))
@@ -6735,40 +6894,49 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
       expand_goto (LABELED_BLOCK_LABEL (EXIT_BLOCK_LABELED_BLOCK (exp)));
       return const0_rtx;
 
-    case LOOP_EXPR:
-      push_temp_slots ();
-      expand_start_loop (1);
-      expand_expr_stmt_value (TREE_OPERAND (exp, 0), 0, 1);
-      expand_end_loop ();
-      pop_temp_slots ();
-
-      return const0_rtx;
-
     case BIND_EXPR:
       {
-       tree vars = TREE_OPERAND (exp, 0);
+       tree block = BIND_EXPR_BLOCK (exp);
+       int mark_ends;
 
-       /* Need to open a binding contour here because
-          if there are any cleanups they must be contained here.  */
-       expand_start_bindings (2);
+       if (TREE_CODE (BIND_EXPR_BODY (exp)) != RTL_EXPR)
+         {
+           /* If we're in functions-as-trees mode, this BIND_EXPR represents
+              the block, so we need to emit NOTE_INSN_BLOCK_* notes.  */
+           mark_ends = (block != NULL_TREE);
+           expand_start_bindings_and_block (mark_ends ? 0 : 2, block);
+         }
+       else
+         {
+           /* If we're not in functions-as-trees mode, we've already emitted
+              those notes into our RTL_EXPR, so we just want to splice our BLOCK
+              into the enclosing one.  */
+           mark_ends = 0;
 
-       /* Mark the corresponding BLOCK for output in its proper place.  */
-       if (TREE_OPERAND (exp, 2) != 0
-           && ! TREE_USED (TREE_OPERAND (exp, 2)))
-         (*lang_hooks.decls.insert_block) (TREE_OPERAND (exp, 2));
+           /* Need to open a binding contour here because
+              if there are any cleanups they must be contained here.  */
+           expand_start_bindings_and_block (2, NULL_TREE);
 
-       /* If VARS have not yet been expanded, expand them now.  */
-       while (vars)
-         {
-           if (!DECL_RTL_SET_P (vars))
-             expand_decl (vars);
-           expand_decl_init (vars);
-           vars = TREE_CHAIN (vars);
+           /* Mark the corresponding BLOCK for output in its proper place.  */
+           if (block)
+             {
+               if (TREE_USED (block))
+                 abort ();
+               lang_hooks.decls.insert_block (block);
+             }
          }
 
-       temp = expand_expr (TREE_OPERAND (exp, 1), target, tmode, modifier);
+       /* If VARS have not yet been expanded, expand them now.  */
+       expand_vars (BIND_EXPR_VARS (exp));
+
+       /* TARGET was clobbered early in this function.  The correct
+          indicator or whether or not we need the value of this 
+          expression is the IGNORE variable.  */
+       temp = expand_expr (BIND_EXPR_BODY (exp),
+                           ignore ? const0_rtx : target,
+                           tmode, modifier);
 
-       expand_end_bindings (TREE_OPERAND (exp, 0), 0, 0);
+       expand_end_bindings (BIND_EXPR_VARS (exp), mark_ends, 0);
 
        return temp;
       }
@@ -6783,6 +6951,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
        }
       preserve_rtl_expr_result (RTL_EXPR_RTL (exp));
       free_temps_for_rtl_expr (exp);
+      if (alt_rtl)
+       *alt_rtl = RTL_EXPR_ALT_RTL (exp);
       return RTL_EXPR_RTL (exp);
 
     case CONSTRUCTOR:
@@ -6819,9 +6989,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
                        && (! MOVE_BY_PIECES_P
                            (tree_low_cst (TYPE_SIZE_UNIT (type), 1),
                             TYPE_ALIGN (type)))
-                       && ((TREE_CODE (type) == VECTOR_TYPE
-                            && !is_zeros_p (exp))
-                           || ! mostly_zeros_p (exp)))))
+                       && ! mostly_zeros_p (exp))))
               || ((modifier == EXPAND_INITIALIZER
                    || modifier == EXPAND_CONST_ADDRESS)
                   && TREE_CONSTANT (exp)))
@@ -6856,19 +7024,15 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
     case INDIRECT_REF:
       {
        tree exp1 = TREE_OPERAND (exp, 0);
-       tree index;
-       tree string = string_constant (exp1, &index);
 
-       /* Try to optimize reads from const strings.  */
-       if (string
-           && TREE_CODE (string) == STRING_CST
-           && TREE_CODE (index) == INTEGER_CST
-           && compare_tree_int (index, TREE_STRING_LENGTH (string)) < 0
-           && GET_MODE_CLASS (mode) == MODE_INT
-           && GET_MODE_SIZE (mode) == 1
-           && modifier != EXPAND_WRITE)
-         return gen_int_mode (TREE_STRING_POINTER (string)
-                              [TREE_INT_CST_LOW (index)], mode);
+       if (modifier != EXPAND_WRITE)
+         {
+           tree t;
+
+           t = fold_read_from_constant_string (exp);
+           if (t)
+             return expand_expr (t, target, tmode, modifier);
+         }
 
        op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
        op0 = memory_address (mode, op0);
@@ -6885,13 +7049,15 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
       }
 
     case ARRAY_REF:
+
+#ifdef ENABLE_CHECKING
       if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) != ARRAY_TYPE)
        abort ();
+#endif
 
       {
        tree array = TREE_OPERAND (exp, 0);
-       tree domain = TYPE_DOMAIN (TREE_TYPE (array));
-       tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
+       tree low_bound = array_ref_low_bound (exp);
        tree index = convert (sizetype, TREE_OPERAND (exp, 1));
        HOST_WIDE_INT i;
 
@@ -6913,14 +7079,13 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
 
        if (modifier != EXPAND_CONST_ADDRESS
            && modifier != EXPAND_INITIALIZER
-           && modifier != EXPAND_MEMORY
-           && 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
-           && GET_MODE_SIZE (mode) == 1)
-         return gen_int_mode (TREE_STRING_POINTER (array)
-                              [TREE_INT_CST_LOW (index)], mode);
+           && modifier != EXPAND_MEMORY)
+         {
+           tree t = fold_read_from_constant_string (exp);
+
+           if (t)
+             return expand_expr (t, target, tmode, modifier);
+         }
 
        /* If this is a constant index into a constant array,
           just get the value from the array.  Handle both the cases when
@@ -7027,7 +7192,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
                    enum machine_mode imode
                      = TYPE_MODE (TREE_TYPE (TREE_PURPOSE (elt)));
 
-                   if (TREE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
+                   if (TYPE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
                      {
                        op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1);
                        op0 = expand_and (imode, op0, op1, target);
@@ -7143,10 +7308,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
              offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
 #endif
 
-           /* A constant address in OP0 can have VOIDmode, we must not try
-              to call force_reg for that case.  Avoid that case.  */
-           if (GET_CODE (op0) == MEM
-               && GET_MODE (op0) == BLKmode
+           if (GET_MODE (op0) == BLKmode
+               /* A constant address in OP0 can have VOIDmode, we must
+                  not try to call force_reg in that case.  */
                && GET_MODE (XEXP (op0, 0)) != VOIDmode
                && bitsize != 0
                && (bitpos % bitsize) == 0
@@ -7193,7 +7357,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
           (which we know to be the width of a basic mode), then
           storing into memory, and changing the mode to BLKmode.  */
        if (mode1 == VOIDmode
-           || GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
+           || REG_P (op0) || GET_CODE (op0) == SUBREG
            || (mode1 != BLKmode && ! direct_load[(int) mode1]
                && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
                && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT
@@ -7203,7 +7367,10 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
               fetch it as a bit field.  */
            || (mode1 != BLKmode
                && (((TYPE_ALIGN (TREE_TYPE (tem)) < GET_MODE_ALIGNMENT (mode)
-                     || (bitpos % GET_MODE_ALIGNMENT (mode) != 0))
+                     || (bitpos % GET_MODE_ALIGNMENT (mode) != 0)
+                     || (GET_CODE (op0) == MEM
+                         && (MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode1)
+                             || (bitpos % GET_MODE_ALIGNMENT (mode1) != 0))))
                     && ((modifier == EXPAND_CONST_ADDRESS
                          || modifier == EXPAND_INITIALIZER)
                         ? STRICT_ALIGNMENT
@@ -7254,7 +7421,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
 
            op0 = validize_mem (op0);
 
-           if (GET_CODE (op0) == MEM && GET_CODE (XEXP (op0, 0)) == REG)
+           if (GET_CODE (op0) == MEM && REG_P (XEXP (op0, 0)))
              mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
 
            op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp,
@@ -7274,12 +7441,19 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
                                            - bitsize),
                                  op0, 1);
 
+           /* If the result type is BLKmode, store the data into a temporary
+              of the appropriate type, but with the mode corresponding to the
+              mode for the data we have (op0's mode).  It's tempting to make
+              this a constant type, since we know it's only being stored once,
+              but that can cause problems if we are taking the address of this
+              COMPONENT_REF because the MEM of any reference via that address
+              will have flags corresponding to the type, which will not
+              necessarily be constant.  */
            if (mode == BLKmode)
              {
-               rtx new = assign_temp (build_qualified_type
-                                      ((*lang_hooks.types.type_for_mode)
-                                       (ext_mode, 0),
-                                       TYPE_QUAL_CONST), 0, 1, 1);
+               rtx new
+                 = assign_stack_temp_for_type
+                   (ext_mode, GET_MODE_BITSIZE (ext_mode), 0, type);
 
                emit_move_insn (new, op0);
                op0 = copy_rtx (new);
@@ -7306,7 +7480,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
          op0 = copy_rtx (op0);
 
        set_mem_attributes (op0, exp, 0);
-       if (GET_CODE (XEXP (op0, 0)) == REG)
+       if (REG_P (XEXP (op0, 0)))
          mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
 
        MEM_VOLATILE_P (op0) |= volatilep;
@@ -7377,7 +7551,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
 
        tree set = TREE_OPERAND (exp, 0);
        tree index = TREE_OPERAND (exp, 1);
-       int iunsignedp = TREE_UNSIGNED (TREE_TYPE (index));
+       int iunsignedp = TYPE_UNSIGNED (TREE_TYPE (index));
        tree set_type = TREE_TYPE (set);
        tree set_low_bound = TYPE_MIN_VALUE (TYPE_DOMAIN (set_type));
        tree set_high_bound = TYPE_MAX_VALUE (TYPE_DOMAIN (set_type));
@@ -7504,8 +7678,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
        {
          if (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
              == BUILT_IN_FRONTEND)
-           return (*lang_hooks.expand_expr) (exp, original_target,
-                                             tmode, modifier);
+           return lang_hooks.expand_expr (exp, original_target,
+                                          tmode, modifier,
+                                          alt_rtl);
          else
            return expand_builtin (exp, target, subtarget, tmode, ignore);
        }
@@ -7536,7 +7711,12 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
            }
 
          if (target == 0)
-           target = assign_temp (type, 0, 1, 1);
+           {
+             if (TYPE_MODE (type) != BLKmode)
+               target = gen_reg_rtx (TYPE_MODE (type));
+             else
+               target = assign_temp (type, 0, 1, 1);
+           }
 
          if (GET_CODE (target) == MEM)
            /* Store data into beginning of memory target.  */
@@ -7544,7 +7724,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
                        adjust_address (target, TYPE_MODE (valtype), 0),
                        modifier == EXPAND_STACK_PARM ? 2 : 0);
 
-         else if (GET_CODE (target) == REG)
+         else if (REG_P (target))
            /* Store this field into a union of the proper type.  */
            store_field (target,
                         MIN ((int_size_in_bytes (TREE_TYPE
@@ -7568,7 +7748,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
          /* If the signedness of the conversion differs and OP0 is
             a promoted SUBREG, clear that indication since we now
             have to do the proper extension.  */
-         if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))) != unsignedp
+         if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))) != unsignedp
              && GET_CODE (op0) == SUBREG)
            SUBREG_PROMOTED_VAR_P (op0) = 0;
 
@@ -7591,7 +7771,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
                                                               inner_mode));
          else
            return convert_modes (mode, inner_mode, op0,
-                                 TREE_UNSIGNED (inner_type));
+                                 TYPE_UNSIGNED (inner_type));
        }
 
       if (modifier == EXPAND_INITIALIZER)
@@ -7600,10 +7780,10 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
       if (target == 0)
        return
          convert_to_mode (mode, op0,
-                          TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+                          TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
       else
        convert_move (target, op0,
-                     TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+                     TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
       return target;
 
     case VIEW_CONVERT_EXPR:
@@ -7867,9 +8047,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
          op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
                             EXPAND_SUM);
 
-         if (GET_CODE (op0) != REG)
+         if (!REG_P (op0))
            op0 = force_operand (op0, NULL_RTX);
-         if (GET_CODE (op0) != REG)
+         if (!REG_P (op0))
            op0 = copy_to_mode_reg (mode, op0);
 
          return gen_rtx_MULT (mode, op0,
@@ -7897,21 +8077,25 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
                   || exact_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))) < 0))
              ||
              (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
-              && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
-                  ==
-                  TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))))
+              && (TYPE_PRECISION (TREE_TYPE
+                                  (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
+                  == TYPE_PRECISION (TREE_TYPE
+                                     (TREE_OPERAND
+                                      (TREE_OPERAND (exp, 0), 0))))
               /* If both operands are extended, they must either both
                  be zero-extended or both be sign-extended.  */
-              && (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
-                  ==
-                  TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))))))
-       {
-         enum machine_mode innermode
-           = TYPE_MODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)));
-         optab other_optab = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
-                       ? smul_widen_optab : umul_widen_optab);
-         this_optab = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
-                       ? umul_widen_optab : smul_widen_optab);
+              && (TYPE_UNSIGNED (TREE_TYPE
+                                 (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
+                  == TYPE_UNSIGNED (TREE_TYPE
+                                    (TREE_OPERAND
+                                     (TREE_OPERAND (exp, 0), 0)))))))
+       {
+         tree op0type = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0));
+         enum machine_mode innermode = TYPE_MODE (op0type);
+         bool zextend_p = TYPE_UNSIGNED (op0type);
+         optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;
+         this_optab = zextend_p ? umul_widen_optab : smul_widen_optab;
+
          if (mode == GET_MODE_WIDER_MODE (innermode))
            {
              if (this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
@@ -7929,7 +8113,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
              else if (other_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
                       && innermode == word_mode)
                {
-                 rtx htem;
+                 rtx htem, hipart;
                  op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
                                     NULL_RTX, VOIDmode, 0);
                  if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
@@ -7942,12 +8126,12 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
                                       NULL_RTX, VOIDmode, 0);
                  temp = expand_binop (mode, other_optab, op0, op1, target,
                                       unsignedp, OPTAB_LIB_WIDEN);
-                 htem = expand_mult_highpart_adjust (innermode,
-                                                     gen_highpart (innermode, temp),
-                                                     op0, op1,
-                                                     gen_highpart (innermode, temp),
-                                                     unsignedp);
-                 emit_move_insn (gen_highpart (innermode, temp), htem);
+                 hipart = gen_highpart (innermode, temp);
+                 htem = expand_mult_highpart_adjust (innermode, hipart,
+                                                     op0, op1, hipart,
+                                                     zextend_p);
+                 if (htem != hipart)
+                   emit_move_insn (hipart, htem);
                  return temp;
                }
            }
@@ -8017,7 +8201,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
        op0 = copy_to_mode_reg (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
                                op0);
       expand_float (target, op0,
-                   TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+                   TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
       return target;
 
     case NEGATE_EXPR:
@@ -8044,7 +8228,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
 
       /* Unsigned abs is simply the operand.  Testing here means we don't
         risk generating incorrect code below.  */
-      if (TREE_UNSIGNED (type))
+      if (TYPE_UNSIGNED (type))
        return op0;
 
       return expand_abs (mode, op0, target, unsignedp,
@@ -8057,7 +8241,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
          || modifier == EXPAND_STACK_PARM
          || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
          || GET_MODE (target) != mode
-         || (GET_CODE (target) == REG
+         || (REG_P (target)
              && REGNO (target) < FIRST_PSEUDO_REGISTER))
        target = gen_reg_rtx (mode);
       expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
@@ -8066,7 +8250,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
       /* First try to do it with a special MIN or MAX instruction.
         If that does not win, use a conditional jump to select the proper
         value.  */
-      this_optab = (TREE_UNSIGNED (type)
+      this_optab = (unsignedp
                    ? (code == MIN_EXPR ? umin_optab : umax_optab)
                    : (code == MIN_EXPR ? smin_optab : smax_optab));
 
@@ -8100,18 +8284,16 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
          && ! can_compare_p (GE, mode, ccp_jump))
        {
          if (code == MAX_EXPR)
-           do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type),
-                                         target, op1, NULL_RTX, op0);
+           do_jump_by_parts_greater_rtx (mode, unsignedp, target, op1,
+                                         NULL_RTX, op0);
          else
-           do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type),
-                                         op1, target, NULL_RTX, op0);
+           do_jump_by_parts_greater_rtx (mode, unsignedp, op1, target,
+                                         NULL_RTX, op0);
        }
       else
        {
-         int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)));
          do_compare_rtx_and_jump (target, op1, code == MAX_EXPR ? GE : LE,
-                                  unsignedp, mode, NULL_RTX, NULL_RTX,
-                                  op0);
+                                  unsignedp, mode, NULL_RTX, NULL_RTX, op0);
        }
       emit_move_insn (target, op1);
       emit_label (op0);
@@ -8181,6 +8363,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
     case UNGT_EXPR:
     case UNGE_EXPR:
     case UNEQ_EXPR:
+    case LTGT_EXPR:
       temp = do_store_flag (exp,
                            modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
                            tmode != VOIDmode ? tmode : mode, 0);
@@ -8190,7 +8373,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
       /* For foo != 0, load foo, and if it is nonzero load 1 instead.  */
       if (code == NE_EXPR && integer_zerop (TREE_OPERAND (exp, 1))
          && original_target
-         && GET_CODE (original_target) == REG
+         && REG_P (original_target)
          && (GET_MODE (original_target)
              == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
        {
@@ -8237,7 +8420,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
              || ! safe_from_p (target, exp, 1)
              /* Make sure we don't have a hard reg (such as function's return
                 value) live across basic blocks, if not optimizing.  */
-             || (!optimize && GET_CODE (target) == REG
+             || (!optimize && REG_P (target)
                  && REGNO (target) < FIRST_PSEUDO_REGISTER)))
        target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
 
@@ -8268,11 +8451,81 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
     case COMPOUND_EXPR:
       expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
       emit_queue ();
-      return expand_expr (TREE_OPERAND (exp, 1),
-                         (ignore ? const0_rtx : target),
-                         VOIDmode, modifier);
+      return expand_expr_real (TREE_OPERAND (exp, 1),
+                              (ignore ? const0_rtx : target),
+                              VOIDmode, modifier, alt_rtl);
+
+    case STATEMENT_LIST:
+      {
+       tree_stmt_iterator iter;
+
+       if (!ignore)
+         abort ();
+
+       for (iter = tsi_start (exp); !tsi_end_p (iter); tsi_next (&iter))
+         expand_expr (tsi_stmt (iter), const0_rtx, VOIDmode, modifier);
+      }
+      return const0_rtx;
 
     case COND_EXPR:
+      /* If it's void, we don't need to worry about computing a value.  */
+      if (VOID_TYPE_P (TREE_TYPE (exp)))
+       {
+         tree pred = TREE_OPERAND (exp, 0);
+         tree then_ = TREE_OPERAND (exp, 1);
+         tree else_ = TREE_OPERAND (exp, 2);
+
+         /* If we do not have any pending cleanups or stack_levels
+            to restore, and at least one arm of the COND_EXPR is a
+            GOTO_EXPR to a local label, then we can emit more efficient
+            code by using jumpif/jumpifnot instead of the 'if' machinery.  */
+         if (! optimize
+             || containing_blocks_have_cleanups_or_stack_level ())
+           ;
+         else if (TREE_CODE (then_) == GOTO_EXPR
+                  && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
+           {
+             jumpif (pred, label_rtx (GOTO_DESTINATION (then_)));
+             return expand_expr (else_, const0_rtx, VOIDmode, 0);
+           }
+         else if (TREE_CODE (else_) == GOTO_EXPR
+                  && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)
+           {
+             jumpifnot (pred, label_rtx (GOTO_DESTINATION (else_)));
+             return expand_expr (then_, const0_rtx, VOIDmode, 0);
+           }
+
+         /* Just use the 'if' machinery.  */
+         expand_start_cond (pred, 0);
+         start_cleanup_deferral ();
+         expand_expr (then_, const0_rtx, VOIDmode, 0);
+
+         exp = else_;
+
+         /* Iterate over 'else if's instead of recursing.  */
+         for (; TREE_CODE (exp) == COND_EXPR; exp = TREE_OPERAND (exp, 2))
+           {
+             expand_start_else ();
+             if (EXPR_HAS_LOCATION (exp))
+               {
+                 emit_line_note (EXPR_LOCATION (exp));
+                 if (cfun->dont_emit_block_notes)
+                   record_block_change (TREE_BLOCK (exp));
+               }
+             expand_elseif (TREE_OPERAND (exp, 0));
+             expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, 0);
+           }
+         /* Don't emit the jump and label if there's no 'else' clause.  */
+         if (TREE_SIDE_EFFECTS (exp))
+           {
+             expand_start_else ();
+             expand_expr (exp, const0_rtx, VOIDmode, 0);
+           }
+         end_cleanup_deferral ();
+         expand_end_cond ();
+         return const0_rtx;
+       }
+
       /* If we would have a "singleton" (see below) were it not for a
         conversion in each arm, bring that conversion back out.  */
       if (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
@@ -8369,13 +8622,13 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
          temp = assign_temp (type, 0, 0, 1);
        else if (original_target
                 && (safe_from_p (original_target, TREE_OPERAND (exp, 0), 1)
-                    || (singleton && GET_CODE (original_target) == REG
+                    || (singleton && REG_P (original_target)
                         && REGNO (original_target) >= FIRST_PSEUDO_REGISTER
                         && original_target == var_rtx (singleton)))
                 && GET_MODE (original_target) == mode
 #ifdef HAVE_conditional_move
                 && (! can_conditionally_move_p (mode)
-                    || GET_CODE (original_target) == REG
+                    || REG_P (original_target)
                     || TREE_ADDRESSABLE (type))
 #endif
                 && (GET_CODE (original_target) != MEM
@@ -8451,7 +8704,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
                   might clobber it.  */
                if ((binary_op
                     && ! safe_from_p (temp, TREE_OPERAND (binary_op, 1), 1))
-                   || (GET_CODE (temp) == REG
+                   || (REG_P (temp)
                        && REGNO (temp) < FIRST_PSEUDO_REGISTER))
                  temp = gen_reg_rtx (mode);
                store_expr (singleton, temp,
@@ -8494,7 +8747,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
                     || TREE_CODE (TREE_OPERAND (exp, 1)) == SAVE_EXPR)
                 && safe_from_p (temp, TREE_OPERAND (exp, 2), 1))
          {
-           if (GET_CODE (temp) == REG
+           if (REG_P (temp)
                && REGNO (temp) < FIRST_PSEUDO_REGISTER)
              temp = gen_reg_rtx (mode);
            store_expr (TREE_OPERAND (exp, 1), temp,
@@ -8519,7 +8772,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
                     || TREE_CODE (TREE_OPERAND (exp, 2)) == SAVE_EXPR)
                 && safe_from_p (temp, TREE_OPERAND (exp, 1), 1))
          {
-           if (GET_CODE (temp) == REG
+           if (REG_P (temp)
                && REGNO (temp) < FIRST_PSEUDO_REGISTER)
              temp = gen_reg_rtx (mode);
            store_expr (TREE_OPERAND (exp, 2), temp,
@@ -8614,8 +8867,6 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
            else
              {
                target = assign_temp (type, 2, 0, 1);
-               /* All temp slots at this level must not conflict.  */
-               preserve_temp_slots (target);
                SET_DECL_RTL (slot, target);
                if (TREE_ADDRESSABLE (slot))
                  put_var_into_stack (slot, /*rescan=*/false);
@@ -8629,7 +8880,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
 
                if (TREE_OPERAND (exp, 2) == 0)
                  TREE_OPERAND (exp, 2)
-                   = (*lang_hooks.maybe_build_cleanup) (slot);
+                   = lang_hooks.maybe_build_cleanup (slot);
                cleanups = TREE_OPERAND (exp, 2);
              }
          }
@@ -8665,7 +8916,12 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
        /* Mark it as expanded.  */
        TREE_OPERAND (exp, 1) = NULL_TREE;
 
-       store_expr (exp1, target, modifier == EXPAND_STACK_PARM ? 2 : 0);
+       if (VOID_TYPE_P (TREE_TYPE (exp1)))
+         /* If the initializer is void, just expand it; it will initialize
+            the object directly.  */
+         expand_expr (exp1, const0_rtx, VOIDmode, 0);
+       else
+         store_expr (exp1, target, modifier == EXPAND_STACK_PARM ? 2 : 0);
 
        expand_decl_cleanup_eh (NULL_TREE, cleanups, CLEANUP_EH_ONLY (exp));
 
@@ -8752,18 +9008,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
     case ADDR_EXPR:
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
-      /* Are we taking the address of a nested function?  */
-      if (TREE_CODE (TREE_OPERAND (exp, 0)) == FUNCTION_DECL
-         && decl_function_context (TREE_OPERAND (exp, 0)) != 0
-         && ! DECL_NO_STATIC_CHAIN (TREE_OPERAND (exp, 0))
-         && ! TREE_STATIC (exp))
-       {
-         op0 = trampoline_address (TREE_OPERAND (exp, 0));
-         op0 = force_operand (op0, target);
-       }
       /* If we are taking the address of something erroneous, just
         return a zero.  */
-      else if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK)
+      if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK)
        return const0_rtx;
       /* If we are taking the address of a constant and are at the
         top level, we have to use output_constant_def since we can't
@@ -8799,7 +9046,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
          if (CONSTANT_P (op0))
            op0 = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
                                   op0);
-         else if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
+         else if (REG_P (op0) || GET_CODE (op0) == SUBREG
                   || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF
                   || GET_CODE (op0) == PARALLEL || GET_CODE (op0) == LO_SUM)
            {
@@ -8889,13 +9136,13 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
        }
 
       if (flag_force_addr
-         && GET_CODE (op0) != REG
+         && !REG_P (op0)
          && modifier != EXPAND_CONST_ADDRESS
          && modifier != EXPAND_INITIALIZER
          && modifier != EXPAND_SUM)
        op0 = force_reg (Pmode, op0);
 
-      if (GET_CODE (op0) == REG
+      if (REG_P (op0)
          && ! REG_USERVAR_P (op0))
        mark_reg_pointer (op0, TYPE_ALIGN (TREE_TYPE (type)));
 
@@ -8990,25 +9237,38 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
        return target;
       }
 
+    case RESX_EXPR:
+      expand_resx_expr (exp);
+      return const0_rtx;
+
     case TRY_CATCH_EXPR:
       {
        tree handler = TREE_OPERAND (exp, 1);
 
        expand_eh_region_start ();
-
        op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
-
-       expand_eh_region_end_cleanup (handler);
+       expand_eh_handler (handler);
 
        return op0;
       }
 
+    case CATCH_EXPR:
+      expand_start_catch (CATCH_TYPES (exp));
+      expand_expr (CATCH_BODY (exp), const0_rtx, VOIDmode, 0);
+      expand_end_catch ();
+      return const0_rtx;
+
+    case EH_FILTER_EXPR:
+      /* Should have been handled in expand_eh_handler.  */
+      abort ();
+
     case TRY_FINALLY_EXPR:
       {
        tree try_block = TREE_OPERAND (exp, 0);
        tree finally_block = TREE_OPERAND (exp, 1);
 
-        if (!optimize || unsafe_for_reeval (finally_block) > 1)
+        if ((!optimize && lang_protect_cleanup_actions == NULL)
+           || unsafe_for_reeval (finally_block) > 1)
          {
            /* In this case, wrapping FINALLY_BLOCK in an UNSAVE_EXPR
               is not sufficient, so we cannot expand the block twice.
@@ -9077,13 +9337,102 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
     case EXC_PTR_EXPR:
       return get_exception_pointer (cfun);
 
+    case FILTER_EXPR:
+      return get_exception_filter (cfun);
+
     case FDESC_EXPR:
       /* Function descriptors are not valid except for as
         initialization constants, and should not be expanded.  */
       abort ();
 
+    case SWITCH_EXPR:
+      expand_start_case (0, SWITCH_COND (exp), integer_type_node,
+                        "switch");
+      if (SWITCH_BODY (exp))
+        expand_expr_stmt (SWITCH_BODY (exp));
+      if (SWITCH_LABELS (exp))
+       {
+         tree duplicate = 0;
+         tree vec = SWITCH_LABELS (exp);
+         size_t i, n = TREE_VEC_LENGTH (vec);
+
+         for (i = 0; i < n; ++i)
+           {
+             tree elt = TREE_VEC_ELT (vec, i);
+             tree controlling_expr_type = TREE_TYPE (SWITCH_COND (exp));
+             tree min_value = TYPE_MIN_VALUE (controlling_expr_type);
+             tree max_value = TYPE_MAX_VALUE (controlling_expr_type);
+             
+             tree case_low = CASE_LOW (elt);
+             tree case_high = CASE_HIGH (elt) ? CASE_HIGH (elt) : case_low;
+             if (case_low && case_high)
+               {
+                 /* Case label is less than minimum for type.  */
+                 if ((tree_int_cst_compare (case_low, min_value) < 0)
+                     && (tree_int_cst_compare (case_high, min_value) < 0))
+                   {
+                     warning ("case label value %d is less than minimum value for type",
+                              TREE_INT_CST (case_low));
+                     continue;
+                   }
+                 
+                 /* Case value is greater than maximum for type.  */
+                 if ((tree_int_cst_compare (case_low, max_value) > 0)
+                     && (tree_int_cst_compare (case_high, max_value) > 0))
+                   {
+                     warning ("case label value %d exceeds maximum value for type",
+                              TREE_INT_CST (case_high));
+                     continue;
+                   }
+                 
+                 /* Saturate lower case label value to minimum.  */
+                 if ((tree_int_cst_compare (case_high, min_value) >= 0)
+                     && (tree_int_cst_compare (case_low, min_value) < 0))
+                   {
+                     warning ("lower value %d in case label range less than minimum value for type",
+                              TREE_INT_CST (case_low));
+                     case_low = min_value;
+                   }
+                 
+                 /* Saturate upper case label value to maximum.  */
+                 if ((tree_int_cst_compare (case_low, max_value) <= 0)
+                     && (tree_int_cst_compare (case_high, max_value) > 0))
+                   {
+                     warning ("upper value %d in case label range exceeds maximum value for type",
+                              TREE_INT_CST (case_high));
+                     case_high = max_value;
+                   }
+               }
+             
+             add_case_node (case_low, case_high, CASE_LABEL (elt), &duplicate, true);
+             if (duplicate)
+               abort ();
+           }
+       }
+      expand_end_case_type (SWITCH_COND (exp), TREE_TYPE (exp));
+      return const0_rtx;
+
+    case LABEL_EXPR:
+      expand_label (TREE_OPERAND (exp, 0));
+      return const0_rtx;
+
+    case CASE_LABEL_EXPR:
+      {
+       tree duplicate = 0;
+       add_case_node (CASE_LOW (exp), CASE_HIGH (exp), CASE_LABEL (exp),
+                      &duplicate, false);
+       if (duplicate)
+         abort ();
+       return const0_rtx;
+      }
+
+    case ASM_EXPR:
+      expand_asm_expr (exp);
+      return const0_rtx;
+
     default:
-      return (*lang_hooks.expand_expr) (exp, original_target, tmode, modifier);
+      return lang_hooks.expand_expr (exp, original_target, tmode,
+                                    modifier, alt_rtl);
     }
 
   /* Here to do an ordinary binary operator, generating an instruction
@@ -9108,18 +9457,18 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode,
 static int
 is_aligning_offset (tree offset, tree exp)
 {
-  /* Strip off any conversions and WITH_RECORD_EXPR nodes.  */
+  /* Strip off any conversions.  */
   while (TREE_CODE (offset) == NON_LVALUE_EXPR
         || TREE_CODE (offset) == NOP_EXPR
-        || TREE_CODE (offset) == CONVERT_EXPR
-        || TREE_CODE (offset) == WITH_RECORD_EXPR)
+        || TREE_CODE (offset) == CONVERT_EXPR)
     offset = TREE_OPERAND (offset, 0);
 
   /* We must now have a BIT_AND_EXPR with a constant that is one less than
      power of 2 and which is larger than BIGGEST_ALIGNMENT.  */
   if (TREE_CODE (offset) != BIT_AND_EXPR
       || !host_integerp (TREE_OPERAND (offset, 1), 1)
-      || compare_tree_int (TREE_OPERAND (offset, 1), BIGGEST_ALIGNMENT) <= 0
+      || compare_tree_int (TREE_OPERAND (offset, 1), 
+                          BIGGEST_ALIGNMENT / BITS_PER_UNIT) <= 0
       || !exact_log2 (tree_low_cst (TREE_OPERAND (offset, 1), 1) + 1) < 0)
     return 0;
 
@@ -9140,13 +9489,8 @@ is_aligning_offset (tree offset, tree exp)
         || TREE_CODE (offset) == CONVERT_EXPR)
     offset = TREE_OPERAND (offset, 0);
 
-  /* This must now be the address either of EXP or of a PLACEHOLDER_EXPR
-     whose type is the same as EXP.  */
-  return (TREE_CODE (offset) == ADDR_EXPR
-         && (TREE_OPERAND (offset, 0) == exp
-             || (TREE_CODE (TREE_OPERAND (offset, 0)) == PLACEHOLDER_EXPR
-                 && (TREE_TYPE (TREE_OPERAND (offset, 0))
-                     == TREE_TYPE (exp)))));
+  /* This must now be the address of EXP.  */
+  return TREE_CODE (offset) == ADDR_EXPR && TREE_OPERAND (offset, 0) == exp;
 }
 \f
 /* Return the tree node if an ARG corresponds to a string constant or zero
@@ -9165,6 +9509,13 @@ string_constant (tree arg, tree *ptr_offset)
       *ptr_offset = size_zero_node;
       return TREE_OPERAND (arg, 0);
     }
+  if (TREE_CODE (arg) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF
+      && TREE_CODE (TREE_OPERAND (TREE_OPERAND (arg, 0), 0)) == STRING_CST)
+    {
+      *ptr_offset = convert (sizetype, TREE_OPERAND (TREE_OPERAND (arg, 0), 1));
+      return TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
+    }
   else if (TREE_CODE (arg) == PLUS_EXPR)
     {
       tree arg0 = TREE_OPERAND (arg, 0);
@@ -9260,7 +9611,7 @@ expand_increment (tree exp, int post, int ignore)
        bad_subreg = 1;
     }
 
-  op0_is_copy = ((GET_CODE (op0) == SUBREG || GET_CODE (op0) == REG)
+  op0_is_copy = ((GET_CODE (op0) == SUBREG || REG_P (op0))
                 && temp != get_last_insn ());
   op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
 
@@ -9331,7 +9682,7 @@ expand_increment (tree exp, int post, int ignore)
     {
       /* We have a true reference to the value in OP0.
         If there is an insn to add or subtract in this mode, queue it.
-        Queueing the increment insn avoids the register shuffling
+        Queuing the increment insn avoids the register shuffling
         that often results if we must increment now and first save
         the old value for subsequent use.  */
 
@@ -9384,7 +9735,7 @@ expand_increment (tree exp, int post, int ignore)
 
   /* Increment however we can.  */
   op1 = expand_binop (mode, this_optab, value, op1, op0,
-                     TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
+                     TYPE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
 
   /* Make sure the value is stored into OP0.  */
   if (op1 != op0)
@@ -9444,7 +9795,7 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
 
   type = TREE_TYPE (arg0);
   operand_mode = TYPE_MODE (type);
-  unsignedp = TREE_UNSIGNED (type);
+  unsignedp = TYPE_UNSIGNED (type);
 
   /* We won't bother with BLKmode store-flag operations because it would mean
      passing a lot of information to emit_store_flag.  */
@@ -9528,6 +9879,9 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
     case UNEQ_EXPR:
       code = UNEQ;
       break;
+    case LTGT_EXPR:
+      code = LTGT;
+      break;
 
     default:
       abort ();
@@ -9553,7 +9907,7 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
       && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
       && integer_pow2p (TREE_OPERAND (arg0, 1)))
     {
-      tree type = (*lang_hooks.types.type_for_mode) (mode, unsignedp);
+      tree type = lang_hooks.types.type_for_mode (mode, unsignedp);
       return expand_expr (fold_single_bit_test (code == NE ? NE_EXPR : EQ_EXPR,
                                                arg0, arg1, type),
                          target, VOIDmode, EXPAND_NORMAL);
@@ -9611,7 +9965,7 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
     }
 
   /* If this failed, we have to do this with set/compare/jump/set code.  */
-  if (GET_CODE (target) != REG
+  if (!REG_P (target)
       || reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
     target = gen_reg_rtx (GET_MODE (target));
 
@@ -9697,7 +10051,7 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
     {
       if (TYPE_MODE (index_type) != index_mode)
        {
-         index_expr = convert ((*lang_hooks.types.type_for_size)
+         index_expr = convert (lang_hooks.types.type_for_size
                                (index_bits, 0), index_expr);
          index_type = TREE_TYPE (index_expr);
        }
@@ -9717,7 +10071,7 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
 
   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)));
+                      op1, TYPE_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);
@@ -9726,7 +10080,7 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
 
   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)));
+                      op2, TYPE_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);
@@ -9778,11 +10132,11 @@ do_tablejump (rtx index, enum machine_mode mode, rtx range, rtx table_label,
   if (mode != Pmode)
     index = convert_to_mode (Pmode, index, 1);
 
-  /* Don't let a MEM slip thru, because then INDEX that comes
+  /* Don't let a MEM slip through, because then INDEX that comes
      out of PIC_CASE_VECTOR_ADDRESS won't be a valid address,
      and break_out_memory_refs will go to work on it and mess it up.  */
 #ifdef PIC_CASE_VECTOR_ADDRESS
-  if (flag_pic && GET_CODE (index) != REG)
+  if (flag_pic && !REG_P (index))
     index = copy_to_mode_reg (Pmode, index);
 #endif
 
@@ -9840,7 +10194,7 @@ try_tablejump (tree index_type, tree index_expr, tree minval, tree range,
                               TYPE_MODE (TREE_TYPE (range)),
                               expand_expr (range, NULL_RTX,
                                            VOIDmode, 0),
-                              TREE_UNSIGNED (TREE_TYPE (range))),
+                              TYPE_UNSIGNED (TREE_TYPE (range))),
                table_label, default_label);
   return 1;
 }
@@ -9885,7 +10239,7 @@ const_vector_from_tree (tree exp)
 
   mode = TYPE_MODE (TREE_TYPE (exp));
 
-  if (is_zeros_p (exp))
+  if (initializer_zerop (exp))
     return CONST0_RTX (mode);
 
   units = GET_MODE_NUNITS (mode);
@@ -9913,5 +10267,4 @@ const_vector_from_tree (tree exp)
 
   return gen_rtx_raw_CONST_VECTOR (mode, v);
 }
-
 #include "gt-expr.h"