OSDN Git Service

PR rtl-optimization/14782
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index f2c21c4..aad7b1c 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,6 +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.
@@ -72,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
@@ -94,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
@@ -150,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);
@@ -160,10 +156,12 @@ 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);
+static void expand_operands (tree, tree, rtx, rtx*, rtx*,
+                            enum expand_modifier);
 static rtx do_store_flag (tree, rtx, enum machine_mode, int);
 #ifdef PUSH_ROUNDING
 static void emit_single_push_insn (enum machine_mode, rtx, tree);
@@ -182,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
@@ -201,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
@@ -233,6 +207,11 @@ enum insn_code movstr_optab[NUM_MACHINE_MODES];
 /* This array records the insn_code of insns to perform block clears.  */
 enum insn_code clrstr_optab[NUM_MACHINE_MODES];
 
+/* These arrays record the insn_code of two different kinds of insns
+   to perform block compares.  */
+enum insn_code cmpstr_optab[NUM_MACHINE_MODES];
+enum insn_code cmpmem_optab[NUM_MACHINE_MODES];
+
 /* SLOW_UNALIGNED_ACCESS is nonzero if unaligned accesses are very slow.  */
 
 #ifndef SLOW_UNALIGNED_ACCESS
@@ -338,15 +317,7 @@ init_expr_once (void)
 void
 init_expr (void)
 {
-  cfun->expr = ggc_alloc (sizeof (struct expr_status));
-
-  pending_chain = 0;
-  pending_stack_adjust = 0;
-  stack_pointer_delta = 0;
-  inhibit_defer_pop = 0;
-  saveregs_value = 0;
-  apply_args_value = 0;
-  forced_labels = 0;
+  cfun->expr = ggc_alloc_cleared (sizeof (struct expr_status));
 }
 
 /* Small sanity check that the queue is empty at the end of a function.  */
@@ -495,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);
 
@@ -528,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.
@@ -557,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.  */
@@ -598,248 +600,32 @@ convert_move (rtx to, rtx from, int unsignedp)
       return;
     }
 
-  if (to_real != from_real)
-    abort ();
-
   if (to_real)
     {
       rtx value, insns;
+      convert_optab tab;
 
-      if (GET_MODE_BITSIZE (from_mode) < GET_MODE_BITSIZE (to_mode))
-       {
-         /* Try converting directly if the insn is supported.  */
-         if ((code = can_extend_p (to_mode, from_mode, 0))
-             != CODE_FOR_nothing)
-           {
-             emit_unop_insn (code, to, from, UNKNOWN);
-             return;
-           }
-       }
-
-#ifdef HAVE_trunchfqf2
-      if (HAVE_trunchfqf2 && from_mode == HFmode && to_mode == QFmode)
-       {
-         emit_unop_insn (CODE_FOR_trunchfqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_trunctqfqf2
-      if (HAVE_trunctqfqf2 && from_mode == TQFmode && to_mode == QFmode)
-       {
-         emit_unop_insn (CODE_FOR_trunctqfqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncsfqf2
-      if (HAVE_truncsfqf2 && from_mode == SFmode && to_mode == QFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncsfqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncdfqf2
-      if (HAVE_truncdfqf2 && from_mode == DFmode && to_mode == QFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncdfqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncxfqf2
-      if (HAVE_truncxfqf2 && from_mode == XFmode && to_mode == QFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncxfqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_trunctfqf2
-      if (HAVE_trunctfqf2 && from_mode == TFmode && to_mode == QFmode)
-       {
-         emit_unop_insn (CODE_FOR_trunctfqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-
-#ifdef HAVE_trunctqfhf2
-      if (HAVE_trunctqfhf2 && from_mode == TQFmode && to_mode == HFmode)
-       {
-         emit_unop_insn (CODE_FOR_trunctqfhf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncsfhf2
-      if (HAVE_truncsfhf2 && from_mode == SFmode && to_mode == HFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncsfhf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncdfhf2
-      if (HAVE_truncdfhf2 && from_mode == DFmode && to_mode == HFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncdfhf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncxfhf2
-      if (HAVE_truncxfhf2 && from_mode == XFmode && to_mode == HFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncxfhf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_trunctfhf2
-      if (HAVE_trunctfhf2 && from_mode == TFmode && to_mode == HFmode)
-       {
-         emit_unop_insn (CODE_FOR_trunctfhf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
+      if (GET_MODE_PRECISION (from_mode) < GET_MODE_PRECISION (to_mode))
+       tab = sext_optab;
+      else if (GET_MODE_PRECISION (from_mode) > GET_MODE_PRECISION (to_mode))
+       tab = trunc_optab;
+      else
+       abort ();
 
-#ifdef HAVE_truncsftqf2
-      if (HAVE_truncsftqf2 && from_mode == SFmode && to_mode == TQFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncsftqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncdftqf2
-      if (HAVE_truncdftqf2 && from_mode == DFmode && to_mode == TQFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncdftqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncxftqf2
-      if (HAVE_truncxftqf2 && from_mode == XFmode && to_mode == TQFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncxftqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_trunctftqf2
-      if (HAVE_trunctftqf2 && from_mode == TFmode && to_mode == TQFmode)
-       {
-         emit_unop_insn (CODE_FOR_trunctftqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
+      /* Try converting directly if the insn is supported.  */
 
-#ifdef HAVE_truncdfsf2
-      if (HAVE_truncdfsf2 && from_mode == DFmode && to_mode == SFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncdfsf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncxfsf2
-      if (HAVE_truncxfsf2 && from_mode == XFmode && to_mode == SFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncxfsf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_trunctfsf2
-      if (HAVE_trunctfsf2 && from_mode == TFmode && to_mode == SFmode)
-       {
-         emit_unop_insn (CODE_FOR_trunctfsf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncxfdf2
-      if (HAVE_truncxfdf2 && from_mode == XFmode && to_mode == DFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncxfdf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_trunctfdf2
-      if (HAVE_trunctfdf2 && from_mode == TFmode && to_mode == DFmode)
+      code = tab->handlers[to_mode][from_mode].insn_code;
+      if (code != CODE_FOR_nothing)
        {
-         emit_unop_insn (CODE_FOR_trunctfdf2, to, from, UNKNOWN);
+         emit_unop_insn (code, to, from,
+                         tab == sext_optab ? FLOAT_EXTEND : FLOAT_TRUNCATE);
          return;
        }
-#endif
-
-      libcall = (rtx) 0;
-      switch (from_mode)
-       {
-       case SFmode:
-         switch (to_mode)
-           {
-           case DFmode:
-             libcall = extendsfdf2_libfunc;
-             break;
-
-           case XFmode:
-             libcall = extendsfxf2_libfunc;
-             break;
-
-           case TFmode:
-             libcall = extendsftf2_libfunc;
-             break;
-
-           default:
-             break;
-           }
-         break;
-
-       case DFmode:
-         switch (to_mode)
-           {
-           case SFmode:
-             libcall = truncdfsf2_libfunc;
-             break;
-
-           case XFmode:
-             libcall = extenddfxf2_libfunc;
-             break;
-
-           case TFmode:
-             libcall = extenddftf2_libfunc;
-             break;
 
-           default:
-             break;
-           }
-         break;
-
-       case XFmode:
-         switch (to_mode)
-           {
-           case SFmode:
-             libcall = truncxfsf2_libfunc;
-             break;
-
-           case DFmode:
-             libcall = truncxfdf2_libfunc;
-             break;
-
-           default:
-             break;
-           }
-         break;
-
-       case TFmode:
-         switch (to_mode)
-           {
-           case SFmode:
-             libcall = trunctfsf2_libfunc;
-             break;
+      /* Otherwise use a libcall.  */
+      libcall = tab->handlers[to_mode][from_mode].libfunc;
 
-           case DFmode:
-             libcall = trunctfdf2_libfunc;
-             break;
-
-           default:
-             break;
-           }
-         break;
-
-       default:
-         break;
-       }
-
-      if (libcall == (rtx) 0)
+      if (!libcall)
        /* This conversion is not implemented yet.  */
        abort ();
 
@@ -848,11 +634,49 @@ convert_move (rtx to, rtx from, int unsignedp)
                                       1, from, from_mode);
       insns = get_insns ();
       end_sequence ();
-      emit_libcall_block (insns, to, value, gen_rtx_FLOAT_TRUNCATE (to_mode,
-                                                                   from));
+      emit_libcall_block (insns, to, value,
+                         tab == trunc_optab ? gen_rtx_FLOAT_TRUNCATE (to_mode,
+                                                                      from)
+                         : gen_rtx_FLOAT_EXTEND (to_mode, from));
       return;
     }
 
+  /* Handle pointer conversion.  */                    /* SPEE 900220.  */
+  /* Targets are expected to provide conversion insns between PxImode and
+     xImode for all MODE_PARTIAL_INT modes they use, but no others.  */
+  if (GET_MODE_CLASS (to_mode) == MODE_PARTIAL_INT)
+    {
+      enum machine_mode full_mode
+       = smallest_mode_for_size (GET_MODE_BITSIZE (to_mode), MODE_INT);
+
+      if (trunc_optab->handlers[to_mode][full_mode].insn_code
+         == CODE_FOR_nothing)
+       abort ();
+
+      if (full_mode != from_mode)
+       from = convert_to_mode (full_mode, from, unsignedp);
+      emit_unop_insn (trunc_optab->handlers[to_mode][full_mode].insn_code,
+                     to, from, UNKNOWN);
+      return;
+    }
+  if (GET_MODE_CLASS (from_mode) == MODE_PARTIAL_INT)
+    {
+      enum machine_mode full_mode
+       = smallest_mode_for_size (GET_MODE_BITSIZE (from_mode), MODE_INT);
+
+      if (sext_optab->handlers[full_mode][from_mode].insn_code
+         == CODE_FOR_nothing)
+       abort ();
+
+      emit_unop_insn (sext_optab->handlers[full_mode][from_mode].insn_code,
+                     to, from, UNKNOWN);
+      if (to_mode == full_mode)
+       return;
+
+      /* else proceed to integer conversions below.  */
+      from_mode = full_mode;
+    }
+
   /* Now both modes are integers.  */
 
   /* Handle expanding beyond a word.  */
@@ -885,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);
@@ -968,126 +796,13 @@ 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);
       return;
     }
 
-  /* Handle pointer conversion.  */                    /* SPEE 900220.  */
-  if (to_mode == PQImode)
-    {
-      if (from_mode != QImode)
-       from = convert_to_mode (QImode, from, unsignedp);
-
-#ifdef HAVE_truncqipqi2
-      if (HAVE_truncqipqi2)
-       {
-         emit_unop_insn (CODE_FOR_truncqipqi2, to, from, UNKNOWN);
-         return;
-       }
-#endif /* HAVE_truncqipqi2 */
-      abort ();
-    }
-
-  if (from_mode == PQImode)
-    {
-      if (to_mode != QImode)
-       {
-         from = convert_to_mode (QImode, from, unsignedp);
-         from_mode = QImode;
-       }
-      else
-       {
-#ifdef HAVE_extendpqiqi2
-         if (HAVE_extendpqiqi2)
-           {
-             emit_unop_insn (CODE_FOR_extendpqiqi2, to, from, UNKNOWN);
-             return;
-           }
-#endif /* HAVE_extendpqiqi2 */
-         abort ();
-       }
-    }
-
-  if (to_mode == PSImode)
-    {
-      if (from_mode != SImode)
-       from = convert_to_mode (SImode, from, unsignedp);
-
-#ifdef HAVE_truncsipsi2
-      if (HAVE_truncsipsi2)
-       {
-         emit_unop_insn (CODE_FOR_truncsipsi2, to, from, UNKNOWN);
-         return;
-       }
-#endif /* HAVE_truncsipsi2 */
-      abort ();
-    }
-
-  if (from_mode == PSImode)
-    {
-      if (to_mode != SImode)
-       {
-         from = convert_to_mode (SImode, from, unsignedp);
-         from_mode = SImode;
-       }
-      else
-       {
-#ifdef HAVE_extendpsisi2
-         if (! unsignedp && HAVE_extendpsisi2)
-           {
-             emit_unop_insn (CODE_FOR_extendpsisi2, to, from, UNKNOWN);
-             return;
-           }
-#endif /* HAVE_extendpsisi2 */
-#ifdef HAVE_zero_extendpsisi2
-         if (unsignedp && HAVE_zero_extendpsisi2)
-           {
-             emit_unop_insn (CODE_FOR_zero_extendpsisi2, to, from, UNKNOWN);
-             return;
-           }
-#endif /* HAVE_zero_extendpsisi2 */
-         abort ();
-       }
-    }
-
-  if (to_mode == PDImode)
-    {
-      if (from_mode != DImode)
-       from = convert_to_mode (DImode, from, unsignedp);
-
-#ifdef HAVE_truncdipdi2
-      if (HAVE_truncdipdi2)
-       {
-         emit_unop_insn (CODE_FOR_truncdipdi2, to, from, UNKNOWN);
-         return;
-       }
-#endif /* HAVE_truncdipdi2 */
-      abort ();
-    }
-
-  if (from_mode == PDImode)
-    {
-      if (to_mode != DImode)
-       {
-         from = convert_to_mode (DImode, from, unsignedp);
-         from_mode = DImode;
-       }
-      else
-       {
-#ifdef HAVE_extendpdidi2
-         if (HAVE_extendpdidi2)
-           {
-             emit_unop_insn (CODE_FOR_extendpdidi2, to, from, UNKNOWN);
-             return;
-           }
-#endif /* HAVE_extendpdidi2 */
-         abort ();
-       }
-    }
-
   /* Now follow all the conversions between integers
      no more than a word long.  */
 
@@ -1100,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));
@@ -1148,153 +863,33 @@ convert_move (rtx to, rtx from, int unsignedp)
          /* No suitable intermediate mode.
             Generate what we need with shifts.  */
          shift_amount = build_int_2 (GET_MODE_BITSIZE (to_mode)
-                                     - GET_MODE_BITSIZE (from_mode), 0);
-         from = gen_lowpart (to_mode, force_reg (from_mode, from));
-         tmp = expand_shift (LSHIFT_EXPR, to_mode, from, shift_amount,
-                             to, unsignedp);
-         tmp = expand_shift (RSHIFT_EXPR, to_mode, tmp, shift_amount,
-                             to, unsignedp);
-         if (tmp != to)
-           emit_move_insn (to, tmp);
-         return;
-       }
-    }
-
-  /* Support special truncate insns for certain modes.  */
-
-  if (from_mode == DImode && to_mode == SImode)
-    {
-#ifdef HAVE_truncdisi2
-      if (HAVE_truncdisi2)
-       {
-         emit_unop_insn (CODE_FOR_truncdisi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
-
-  if (from_mode == DImode && to_mode == HImode)
-    {
-#ifdef HAVE_truncdihi2
-      if (HAVE_truncdihi2)
-       {
-         emit_unop_insn (CODE_FOR_truncdihi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
-
-  if (from_mode == DImode && to_mode == QImode)
-    {
-#ifdef HAVE_truncdiqi2
-      if (HAVE_truncdiqi2)
-       {
-         emit_unop_insn (CODE_FOR_truncdiqi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
-
-  if (from_mode == SImode && to_mode == HImode)
-    {
-#ifdef HAVE_truncsihi2
-      if (HAVE_truncsihi2)
-       {
-         emit_unop_insn (CODE_FOR_truncsihi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
-
-  if (from_mode == SImode && to_mode == QImode)
-    {
-#ifdef HAVE_truncsiqi2
-      if (HAVE_truncsiqi2)
-       {
-         emit_unop_insn (CODE_FOR_truncsiqi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
-
-  if (from_mode == HImode && to_mode == QImode)
-    {
-#ifdef HAVE_trunchiqi2
-      if (HAVE_trunchiqi2)
-       {
-         emit_unop_insn (CODE_FOR_trunchiqi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
-
-  if (from_mode == TImode && to_mode == DImode)
-    {
-#ifdef HAVE_trunctidi2
-      if (HAVE_trunctidi2)
-       {
-         emit_unop_insn (CODE_FOR_trunctidi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
-
-  if (from_mode == TImode && to_mode == SImode)
-    {
-#ifdef HAVE_trunctisi2
-      if (HAVE_trunctisi2)
-       {
-         emit_unop_insn (CODE_FOR_trunctisi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
-
-  if (from_mode == TImode && to_mode == HImode)
-    {
-#ifdef HAVE_trunctihi2
-      if (HAVE_trunctihi2)
-       {
-         emit_unop_insn (CODE_FOR_trunctihi2, to, from, UNKNOWN);
+                                     - GET_MODE_BITSIZE (from_mode), 0);
+         from = gen_lowpart (to_mode, force_reg (from_mode, from));
+         tmp = expand_shift (LSHIFT_EXPR, to_mode, from, shift_amount,
+                             to, unsignedp);
+         tmp = expand_shift (RSHIFT_EXPR, to_mode, tmp, shift_amount,
+                             to, unsignedp);
+         if (tmp != to)
+           emit_move_insn (to, tmp);
          return;
        }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
     }
 
-  if (from_mode == TImode && to_mode == QImode)
+  /* Support special truncate insns for certain modes.  */
+  if (trunc_optab->handlers[to_mode][from_mode].insn_code != CODE_FOR_nothing)
     {
-#ifdef HAVE_trunctiqi2
-      if (HAVE_trunctiqi2)
-       {
-         emit_unop_insn (CODE_FOR_trunctiqi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
+      emit_unop_insn (trunc_optab->handlers[to_mode][from_mode].insn_code,
+                     to, from, UNKNOWN);
       return;
     }
 
   /* Handle truncation of volatile memrefs, and so on;
      the things that couldn't be truncated directly,
-     and for which there was no special instruction.  */
+     and for which there was no special instruction.
+
+     ??? Code above formerly short-circuited this, for most integer
+     mode pairs, with a force_reg in from_mode followed by a recursive
+     call to this routine.  Appears always to have been wrong.  */
   if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode))
     {
       rtx temp = force_reg (to_mode, gen_lowpart (to_mode, from));
@@ -1391,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,6 +1014,15 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
       return gen_lowpart (mode, x);
     }
 
+  /* Converting from integer constant into mode is always equivalent to an
+     subreg operation.  */
+  if (VECTOR_MODE_P (mode) && GET_MODE (x) == VOIDmode)
+    {
+      if (GET_MODE_BITSIZE (mode) != GET_MODE_BITSIZE (oldmode))
+       abort ();
+      return simplify_gen_subreg (mode, x, oldmode, 0);
+    }
+
   temp = gen_reg_rtx (mode);
   convert_move (temp, x, unsignedp);
   return temp;
@@ -1796,56 +1400,46 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
 static bool
 block_move_libcall_safe_for_call_parm (void)
 {
+  /* If arguments are pushed on the stack, then they're safe.  */
   if (PUSH_ARGS)
     return true;
-  else
-    {
-      /* Check to see whether memcpy takes all register arguments.  */
-      static enum {
-       takes_regs_uninit, takes_regs_no, takes_regs_yes
-      } takes_regs = takes_regs_uninit;
-
-      switch (takes_regs)
-       {
-       case takes_regs_uninit:
-         {
-           CUMULATIVE_ARGS args_so_far;
-           tree fn, arg;
-
-           fn = emit_block_move_libcall_fn (false);
-           INIT_CUMULATIVE_ARGS (args_so_far, TREE_TYPE (fn), NULL_RTX, 0);
 
-           arg = TYPE_ARG_TYPES (TREE_TYPE (fn));
-           for ( ; arg != void_list_node ; arg = TREE_CHAIN (arg))
-             {
-               enum machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
-               rtx tmp = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
-               if (!tmp || !REG_P (tmp))
-                 goto fail_takes_regs;
-#ifdef FUNCTION_ARG_PARTIAL_NREGS
-               if (FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode,
-                                               NULL_TREE, 1))
-                 goto fail_takes_regs;
+  /* If registers go on the stack anyway, any argument is sure to clobber
+     an outgoing argument.  */
+#if defined (REG_PARM_STACK_SPACE) && defined (OUTGOING_REG_PARM_STACK_SPACE)
+  {
+    tree fn = emit_block_move_libcall_fn (false);
+    (void) fn;
+    if (REG_PARM_STACK_SPACE (fn) != 0)
+      return false;
+  }
 #endif
-               FUNCTION_ARG_ADVANCE (args_so_far, mode, NULL_TREE, 1);
-             }
-         }
-         takes_regs = takes_regs_yes;
-         /* FALLTHRU */
 
-       case takes_regs_yes:
-         return true;
+  /* If any argument goes in memory, then it might clobber an outgoing
+     argument.  */
+  {
+    CUMULATIVE_ARGS args_so_far;
+    tree fn, arg;
 
-       fail_takes_regs:
-         takes_regs = takes_regs_no;
-         /* FALLTHRU */
-       case takes_regs_no:
-         return false;
+    fn = emit_block_move_libcall_fn (false);
+    INIT_CUMULATIVE_ARGS (args_so_far, TREE_TYPE (fn), NULL_RTX, 0, 3);
 
-       default:
-         abort ();
-       }
-    }
+    arg = TYPE_ARG_TYPES (TREE_TYPE (fn));
+    for ( ; arg != void_list_node ; arg = TREE_CHAIN (arg))
+      {
+       enum machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
+       rtx tmp = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
+       if (!tmp || !REG_P (tmp))
+         return false;
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+       if (FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode,
+                                       NULL_TREE, 1))
+         return false;
+#endif
+       FUNCTION_ARG_ADVANCE (args_so_far, mode, NULL_TREE, 1);
+      }
+  }
+  return true;
 }
 
 /* A subroutine of emit_block_move.  Expand a movstr pattern;
@@ -1855,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.  */
@@ -1904,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
@@ -1912,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;
 }
 
@@ -1951,10 +1546,8 @@ emit_block_move_via_libcall (rtx dst, rtx src, rtx size)
   dst_addr = copy_to_mode_reg (Pmode, XEXP (dst, 0));
   src_addr = copy_to_mode_reg (Pmode, XEXP (src, 0));
 
-#ifdef POINTERS_EXTEND_UNSIGNED
   dst_addr = convert_memory_address (ptr_mode, dst_addr);
   src_addr = convert_memory_address (ptr_mode, src_addr);
-#endif
 
   dst_tree = make_tree (ptr_type_node, dst_addr);
   src_tree = make_tree (ptr_type_node, src_addr);
@@ -1997,7 +1590,6 @@ emit_block_move_via_libcall (rtx dst, rtx src, rtx size)
   call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
   call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
                     call_expr, arg_list, NULL_TREE);
-  TREE_SIDE_EFFECTS (call_expr) = 1;
 
   retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
 
@@ -2101,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);
 
@@ -2119,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.
@@ -2245,7 +1832,7 @@ gen_group_rtx (rtx orig)
 /* Emit code to move a block ORIG_SRC of type TYPE to a block DST,
    where DST is non-consecutive registers represented by a PARALLEL.
    SSIZE represents the total size of block ORIG_SRC in bytes, or -1
-   if not known.  */ 
+   if not known.  */
 
 void
 emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
@@ -2333,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);
@@ -2351,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;
@@ -2360,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,
@@ -2534,10 +2124,10 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
    set of registers starting with SRCREG into TGTBLK.  If TGTBLK
    is null, a stack temporary is created.  TGTBLK is returned.
 
-   The primary purpose of this routine is to handle functions
-   that return BLKmode structures in registers.  Some machines
-   (the PA for example) want to return all small structures
-   in registers regardless of the structure's alignment.  */
+   The purpose of this routine is to handle functions that return
+   BLKmode structures in registers.  Some machines (the PA for example)
+   want to return all small structures in registers regardless of the
+   structure's alignment.  */
 
 rtx
 copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
@@ -2545,7 +2135,7 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
   unsigned HOST_WIDE_INT bytes = int_size_in_bytes (type);
   rtx src = NULL, dst = NULL;
   unsigned HOST_WIDE_INT bitsize = MIN (TYPE_ALIGN (type), BITS_PER_WORD);
-  unsigned HOST_WIDE_INT bitpos, xbitpos, big_endian_correction = 0;
+  unsigned HOST_WIDE_INT bitpos, xbitpos, padding_correction = 0;
 
   if (tgtblk == 0)
     {
@@ -2561,15 +2151,22 @@ 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));
-
-  /* Structures whose size is not a multiple of a word are aligned
-     to the least significant byte (to the right).  On a BYTES_BIG_ENDIAN
-     machine, this means we must skip the empty high order bytes when
-     calculating the bit offset.  */
-  if (BYTES_BIG_ENDIAN
-      && bytes % UNITS_PER_WORD)
-    big_endian_correction
+    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,
+     set PADDING_CORRECTION to the number of bits to skip.
+
+     In most ABIs, the structure will be returned at the least end of
+     the register, which translates to right padding on little-endian
+     targets and left padding on big-endian targets.  The opposite
+     holds if the structure is returned at the most significant
+     end of the register.  */
+  if (bytes % UNITS_PER_WORD != 0
+      && (targetm.calls.return_in_msb (type)
+         ? !BYTES_BIG_ENDIAN
+         : BYTES_BIG_ENDIAN))
+    padding_correction
       = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) * BITS_PER_UNIT));
 
   /* Copy the structure BITSIZE bites at a time.
@@ -2577,15 +2174,15 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
      We could probably emit more efficient code for machines which do not use
      strict alignment, but it doesn't seem worth the effort at the current
      time.  */
-  for (bitpos = 0, xbitpos = big_endian_correction;
+  for (bitpos = 0, xbitpos = padding_correction;
        bitpos < bytes * BITS_PER_UNIT;
        bitpos += bitsize, xbitpos += bitsize)
     {
       /* We need a new source operand each time xbitpos is on a
-        word boundary and when xbitpos == big_endian_correction
+        word boundary and when xbitpos == padding_correction
         (the first time through).  */
       if (xbitpos % BITS_PER_WORD == 0
-         || xbitpos == big_endian_correction)
+         || xbitpos == padding_correction)
        src = operand_subword_force (srcreg, xbitpos / BITS_PER_WORD,
                                     GET_MODE (srcreg));
 
@@ -2613,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 ();
 
@@ -2653,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);
     }
 }
@@ -3111,7 +2708,6 @@ clear_storage_via_libcall (rtx object, rtx size)
   call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
   call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
                     call_expr, arg_list, NULL_TREE);
-  TREE_SIDE_EFFECTS (call_expr) = 1;
 
   retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
 
@@ -3205,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))
@@ -3249,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)))
@@ -3391,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);
@@ -3489,6 +3079,17 @@ emit_move_insn_1 (rtx x, rtx y)
       return emit_insn (GEN_FCN (insn_code) (x, y));
     }
 
+  /* Try using a move pattern for the corresponding integer mode.  This is
+     only safe when simplify_subreg can convert MODE constants into integer
+     constants.  At present, it can only do this reliably if the value
+     fits within a HOST_WIDE_INT.  */
+  else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+          && (submode = int_mode_for_mode (mode)) != BLKmode
+          && mov_optab->handlers[submode].insn_code != CODE_FOR_nothing)
+    return emit_insn (GEN_FCN (mov_optab->handlers[submode].insn_code)
+                     (simplify_gen_subreg (submode, x, mode, 0),
+                      simplify_gen_subreg (submode, y, mode, 0)));
+
   /* This will handle any multi-word or full-word mode that lacks a move_insn
      pattern.  However, you will get better code if you define such patterns,
      even if they must turn into multiple assembler instructions.  */
@@ -3647,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;
@@ -3675,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
     {
@@ -3869,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 ();
 
@@ -4026,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);
 
@@ -4115,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.  */
@@ -4206,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)
@@ -4229,7 +3840,11 @@ expand_assignment (tree to, tree from, int want_value)
        }
 
       if (TREE_CODE (to) == COMPONENT_REF
-         && TREE_READONLY (TREE_OPERAND (to, 1)))
+         && TREE_READONLY (TREE_OPERAND (to, 1))
+         /* We can't assert that a MEM won't be set more than once
+            if the component is not addressable because another
+            non-addressable component may be referenced by the same MEM.  */
+         && ! (GET_CODE (to_rtx) == MEM && ! can_address_p (to)))
        {
          if (to_rtx == orig_to_rtx)
            to_rtx = copy_rtx (to_rtx);
@@ -4260,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);
     }
 
@@ -4274,10 +3889,10 @@ expand_assignment (tree to, tree from, int want_value)
      since it might be a promoted variable where the zero- or sign- extension
      needs to be done.  Handling this in the normal way is safe because no
      computation is done before the call.  */
-  if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from)
+  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;
 
@@ -4295,11 +3910,8 @@ expand_assignment (tree to, tree from, int want_value)
        emit_block_move (to_rtx, value, expr_size (from), BLOCK_OP_NORMAL);
       else
        {
-#ifdef POINTERS_EXTEND_UNSIGNED
-         if (POINTER_TYPE_P (TREE_TYPE (to))
-             && GET_MODE (to_rtx) != GET_MODE (value))
+         if (POINTER_TYPE_P (TREE_TYPE (to)))
            value = convert_memory_address (GET_MODE (to_rtx), value);
-#endif
          emit_move_insn (to_rtx, value);
        }
       preserve_temp_slots (to_rtx);
@@ -4316,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;
 
@@ -4353,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,
@@ -4361,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);
@@ -4410,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;
 
@@ -4529,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);
@@ -4591,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.
@@ -4600,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)
@@ -4616,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:
@@ -4637,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,
@@ -4693,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));
@@ -4715,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,
@@ -4742,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.  */
@@ -4757,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);
 
@@ -4765,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 ();
     }
 }
 
@@ -4818,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.
@@ -4861,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.  */
@@ -4929,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)));
@@ -4941,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)))
        {
@@ -4981,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))
@@ -5007,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)
@@ -5040,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
@@ -5052,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);
                }
 
@@ -5084,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)
@@ -5116,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
        {
@@ -5163,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)
            {
@@ -5193,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)
@@ -5209,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)
@@ -5248,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);
 
@@ -5268,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
@@ -5289,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);
                }
            }
@@ -5305,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);
 
@@ -5322,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)
@@ -5337,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.  */
@@ -5409,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
@@ -5479,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);
@@ -5572,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);
@@ -5595,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
@@ -5606,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.  */
@@ -5702,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
@@ -5758,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
@@ -5769,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));
@@ -5811,8 +5598,8 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
             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);
+         else
+           this_offset = SUBSTITUTE_PLACEHOLDER_IN_EXPR (this_offset, exp);
 
          offset = size_binop (PLUS_EXPR, offset, this_offset);
          bit_offset = size_binop (PLUS_EXPR, bit_offset,
@@ -5838,35 +5625,16 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
            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);
-
+         /* If the index has a self-referential type, instantiate it with
+            the object; likewise for the component size.  */
+         index = SUBSTITUTE_PLACEHOLDER_IN_EXPR (index, exp);
+         unit_size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (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.  */
@@ -5951,6 +5719,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
@@ -5973,10 +5755,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)
        {
@@ -5992,7 +5774,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)
        {
@@ -6042,7 +5824,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);
@@ -6107,14 +5889,14 @@ 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;
     }
 
   /* A SAVE_EXPR might appear many times in the expression passed to the
      top-level safe_from_p call, and if it has a complex subexpression,
      examining it multiple times could result in a combinatorial explosion.
-     E.g. on an Alpha running at least 200MHz, a Fortran test case compiled
+     E.g. on an Alpha running at least 200MHz, a Fortran testcase compiled
      with optimization took about 28 minutes to compile -- even though it was
      only a few lines long.  So we mark each SAVE_EXPR we see with TREE_PRIVATE
      and turn that off when we are done.  We keep a list of the SAVE_EXPRs
@@ -6168,7 +5950,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);
@@ -6214,7 +5996,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;
@@ -6280,7 +6062,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;
     }
 
@@ -6291,7 +6073,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;
        }
@@ -6324,60 +6106,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.  */
@@ -6393,7 +6121,7 @@ highest_pow2_factor (tree exp)
       /* We can find the lowest bit that's a one.  If the low
         HOST_BITS_PER_WIDE_INT bits are zero, return BIGGEST_ALIGNMENT.
         We need to handle this case since we can find it in a COND_EXPR,
-        a MIN_EXPR, or a MAX_EXPR.  If the constant overlows, we have an
+        a MIN_EXPR, or a MAX_EXPR.  If the constant overflows, we have an
         erroneous program, so return BIGGEST_ALIGNMENT to avoid any
         later ICE.  */
       if (TREE_CONSTANT_OVERFLOW (exp))
@@ -6430,7 +6158,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:
@@ -6448,82 +6176,115 @@ 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;
+
+  if (TREE_STATIC (var))
+    /* If this is an inlined copy of a static local variable,
+       look up the original decl.  */
+    var = DECL_ORIGIN (var);
 
-  for (placeholder_expr
-       = plist && *plist ? TREE_CHAIN (*plist) : placeholder_list;
-       placeholder_expr != 0;
-       placeholder_expr = TREE_CHAIN (placeholder_expr))
+  if (TREE_STATIC (var)
+      ? !TREE_ASM_WRITTEN (var)
+      : !DECL_RTL_SET_P (var))
     {
-      tree need_type = TYPE_MAIN_VARIANT (type);
-      tree elt;
+      if (TREE_CODE (var) == VAR_DECL && DECL_DEFER_OUTPUT (var))
+       {
+         /* Prepare a mem & address for the decl.  */
+         rtx x;
+                   
+         if (TREE_STATIC (var))
+           abort ();
 
-      /* 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;
-         }
+         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 ();
+    }
+}
 
-      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);
-         }
+/* 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);
     }
+}
 
-  return 0;
+/* Subroutine of expand_expr.  Expand the two operands of a binary
+   expression EXP0 and EXP1 placing the results in OP0 and OP1.
+   The value may be stored in TARGET if TARGET is nonzero.  The
+   MODIFIER argument is as documented by expand_expr.  */
+
+static void
+expand_operands (tree exp0, tree exp1, rtx target, rtx *op0, rtx *op1,
+                enum expand_modifier modifier)
+{
+  if (! safe_from_p (target, exp1, 1))
+    target = 0;
+  if (operand_equal_p (exp0, exp1, 0))
+    {
+      *op0 = expand_expr (exp0, target, VOIDmode, modifier);
+      *op1 = copy_rtx (*op0);
+    }
+  else
+    {
+      /* If we need to preserve evaluation order, copy exp0 into its own
+        temporary variable so that it can't be clobbered by exp1.  */
+      if (flag_evaluation_order && TREE_SIDE_EFFECTS (exp1))
+       exp0 = save_expr (exp0);
+      *op0 = expand_expr (exp0, target, VOIDmode, modifier);
+      *op1 = expand_expr (exp1, NULL_RTX, VOIDmode, modifier);
+    }
 }
+
 \f
 /* expand_expr: generate code for computing expression EXP.
    An rtx for the computed value is returned.  The value is never null.
@@ -6556,23 +6317,108 @@ find_placeholder (tree exp, tree *plist)
    It also makes a ZERO_EXTEND or SIGN_EXTEND instead of emitting extend insns.
    This is used for outputting expressions used in initializers.
 
-   EXPAND_CONST_ADDRESS says that it is okay to return a MEM
-   with a constant address even if that address is not normally legitimate.
-   EXPAND_INITIALIZER and EXPAND_SUM also have this effect.
+   EXPAND_CONST_ADDRESS says that it is okay to return a MEM
+   with a constant address even if that address is not normally legitimate.
+   EXPAND_INITIALIZER and EXPAND_SUM also have this effect.
+
+   EXPAND_STACK_PARM is used when expanding to a TARGET on the stack for
+   a call parameter.  Such targets require special care as we haven't yet
+   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.  
+
+   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_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));
+           }
+       }
+    }
 
-   EXPAND_STACK_PARM is used when expanding to a TARGET on the stack for
-   a call parameter.  Such targets require special care as we haven't yet
-   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.  */
+  return ret;
+}
 
-rtx
-expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier modifier)
+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;
@@ -6580,16 +6426,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
   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;
@@ -6652,49 +6491,6 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       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
@@ -6703,9 +6499,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
      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)))
+      && ! (code == CALL_EXPR && aggregate_value_p (exp, exp)))
     target = 0;
 
   switch (code)
@@ -6713,28 +6509,22 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
     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;
       }
 
     case PARM_DECL:
       if (!DECL_RTL_SET_P (exp))
        {
-         error ("%Hprior parameter's size depends on '%D'",
-                 &DECL_SOURCE_LOCATION (exp), exp);
+         error ("%Jprior parameter's size depends on '%D'", exp, exp);
          return CONST0_RTX (mode);
        }
 
@@ -6770,13 +6560,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       /* 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))))
@@ -6787,7 +6571,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          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);
@@ -6806,7 +6590,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
         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
@@ -6820,15 +6604,19 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
               && (! 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;
@@ -6838,7 +6626,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
         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
@@ -6930,20 +6718,6 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                                      copy_rtx (XEXP (temp, 0)));
       return temp;
 
-    case EXPR_WITH_FILE_LOCATION:
-      {
-       rtx to_return;
-       location_t saved_loc = input_location;
-       input_filename = EXPR_WFL_FILENAME (exp);
-       input_line = EXPR_WFL_LINENO (exp);
-       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), target, tmode, modifier);
-       input_location = saved_loc;
-       return to_return;
-      }
-
     case SAVE_EXPR:
       context = decl_function_context (exp);
 
@@ -6952,11 +6726,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       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.  */
@@ -6967,7 +6737,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          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);
@@ -6989,7 +6759,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                                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);
 
@@ -6998,7 +6768,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
             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);
@@ -7019,7 +6789,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
         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.  */
@@ -7037,35 +6807,10 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        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));
@@ -7073,10 +6818,11 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        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))
@@ -7092,40 +6838,49 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       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;
       }
@@ -7140,6 +6895,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        }
       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:
@@ -7176,9 +6933,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                        && (! 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)))
@@ -7213,19 +6968,15 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
     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);
@@ -7242,8 +6993,11 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       }
 
     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);
@@ -7270,14 +7024,13 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
 
        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
@@ -7312,7 +7065,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                 && modifier != EXPAND_MEMORY
                 && TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
                 && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
-                && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK)
+                && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK
+                && targetm.binds_local_p (array))
          {
            if (TREE_CODE (index) == INTEGER_CST)
              {
@@ -7383,7 +7137,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                    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);
@@ -7477,7 +7231,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                                          (TYPE_QUALS (TREE_TYPE (tem))
                                           | TYPE_QUAL_CONST));
                rtx memloc = assign_temp (nt, 1, 1, 1);
-               
+
                emit_move_insn (memloc, op0);
                op0 = memloc;
              }
@@ -7499,10 +7253,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
              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
@@ -7549,7 +7302,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
           (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
@@ -7559,7 +7312,10 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
               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
@@ -7584,6 +7340,12 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
 
            if (ext_mode == BLKmode)
              {
+               if (target == 0)
+                 target = assign_temp (type, 0, 1, 1);
+
+               if (bitsize == 0)
+                 return target;
+
                /* In this case, BITPOS must start at a byte boundary and
                   TARGET, if specified, must be a MEM.  */
                if (GET_CODE (op0) != MEM
@@ -7591,11 +7353,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                    || bitpos % BITS_PER_UNIT != 0)
                  abort ();
 
-               op0 = adjust_address (op0, VOIDmode, bitpos / BITS_PER_UNIT);
-               if (target == 0)
-                 target = assign_temp (type, 0, 1, 1);
-
-               emit_block_move (target, op0,
+               emit_block_move (target,
+                                adjust_address (op0, VOIDmode,
+                                                bitpos / BITS_PER_UNIT),
                                 GEN_INT ((bitsize + BITS_PER_UNIT - 1)
                                          / BITS_PER_UNIT),
                                 (modifier == EXPAND_STACK_PARM
@@ -7606,7 +7366,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
 
            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,
@@ -7626,12 +7386,19 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                                            - 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);
@@ -7658,7 +7425,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          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;
@@ -7729,7 +7496,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
 
        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));
@@ -7856,8 +7623,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        {
          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);
        }
@@ -7888,7 +7656,12 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
            }
 
          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.  */
@@ -7896,7 +7669,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                        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
@@ -7920,7 +7693,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          /* 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;
 
@@ -7943,7 +7716,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                                                               inner_mode));
          else
            return convert_modes (mode, inner_mode, op0,
-                                 TREE_UNSIGNED (inner_type));
+                                 TYPE_UNSIGNED (inner_type));
        }
 
       if (modifier == EXPAND_INITIALIZER)
@@ -7952,10 +7725,10 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       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:
@@ -8111,11 +7884,11 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                {
                  op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
                                     VOIDmode, modifier);
-                 /* Don't go to both_summands if modifier
-                    says it's not right to return a PLUS.  */
-                 if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
-                   goto binop2;
-                 goto both_summands;
+                 /* Return a PLUS if modifier says it's OK.  */
+                 if (modifier == EXPAND_SUM
+                     || modifier == EXPAND_INITIALIZER)
+                   return simplify_gen_binary (PLUS, mode, op0, op1);
+                 goto binop2;
                }
              /* Use immed_double_const to ensure that the constant is
                 truncated according to the mode of OP1, then sign extended
@@ -8132,9 +7905,6 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
            }
        }
 
-      if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
-       subtarget = 0;
-
       /* No sense saving up arithmetic to be done
         if it's all in the wrong mode to form part of an address.
         And force_operand won't know whether to sign-extend or
@@ -8142,12 +7912,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       if ((modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
          || mode != ptr_mode)
        {
-         op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-         if (! operand_equal_p (TREE_OPERAND (exp, 0),
-                                TREE_OPERAND (exp, 1), 0))
-           op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
-         else
-           op1 = op0;
+         expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                          subtarget, &op0, &op1, 0);
          if (op0 == const0_rtx)
            return op1;
          if (op1 == const0_rtx)
@@ -8155,62 +7921,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          goto binop2;
        }
 
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, modifier);
-      if (! operand_equal_p (TREE_OPERAND (exp, 0),
-                            TREE_OPERAND (exp, 1), 0))
-       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
-                          VOIDmode, modifier);
-      else
-       op1 = op0;
-
-      /* We come here from MINUS_EXPR when the second operand is a
-         constant.  */
-    both_summands:
-      /* Make sure any term that's a sum with a constant comes last.  */
-      if (GET_CODE (op0) == PLUS
-         && CONSTANT_P (XEXP (op0, 1)))
-       {
-         temp = op0;
-         op0 = op1;
-         op1 = temp;
-       }
-      /* If adding to a sum including a constant,
-        associate it to put the constant outside.  */
-      if (GET_CODE (op1) == PLUS
-         && CONSTANT_P (XEXP (op1, 1)))
-       {
-         rtx constant_term = const0_rtx;
-
-         temp = simplify_binary_operation (PLUS, mode, XEXP (op1, 0), op0);
-         if (temp != 0)
-           op0 = temp;
-         /* Ensure that MULT comes first if there is one.  */
-         else if (GET_CODE (op0) == MULT)
-           op0 = gen_rtx_PLUS (mode, op0, XEXP (op1, 0));
-         else
-           op0 = gen_rtx_PLUS (mode, XEXP (op1, 0), op0);
-
-         /* Let's also eliminate constants from op0 if possible.  */
-         op0 = eliminate_constant_term (op0, &constant_term);
-
-         /* CONSTANT_TERM and XEXP (op1, 1) are known to be constant, so
-            their sum should be a constant.  Form it into OP1, since the
-            result we want will then be OP0 + OP1.  */
-
-         temp = simplify_binary_operation (PLUS, mode, constant_term,
-                                           XEXP (op1, 1));
-         if (temp != 0)
-           op1 = temp;
-         else
-           op1 = gen_rtx_PLUS (mode, constant_term, XEXP (op1, 1));
-       }
-
-      /* Put a constant term last and put a multiplication first.  */
-      if (CONSTANT_P (op0) || GET_CODE (op1) == MULT)
-       temp = op1, op1 = op0, op0 = temp;
-
-      temp = simplify_binary_operation (PLUS, mode, op0, op1);
-      return temp ? temp : gen_rtx_PLUS (mode, op0, op1);
+      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                      subtarget, &op0, &op1, modifier);
+      return simplify_gen_binary (PLUS, mode, op0, op1);
 
     case MINUS_EXPR:
       /* For initializers, we are allowed to return a MINUS of two
@@ -8222,10 +7935,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          && really_constant_p (TREE_OPERAND (exp, 0))
          && really_constant_p (TREE_OPERAND (exp, 1)))
        {
-         rtx op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode,
-                                modifier);
-         rtx op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode,
-                                modifier);
+         expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                          NULL_RTX, &op0, &op1, modifier);
 
          /* If the last operand is a CONST_INT, use plus_constant of
             the negated constant.  Else make the MINUS.  */
@@ -8247,17 +7958,14 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          || mode != ptr_mode)
        goto binop;
 
-      if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
-       subtarget = 0;
-
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, modifier);
-      op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, modifier);
+      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                      subtarget, &op0, &op1, modifier);
 
       /* Convert A - const to A + (-const).  */
       if (GET_CODE (op1) == CONST_INT)
        {
          op1 = negate_rtx (mode, op1);
-         goto both_summands;
+         return simplify_gen_binary (PLUS, mode, op0, op1);
        }
 
       goto binop2;
@@ -8284,19 +7992,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
                             EXPAND_SUM);
 
-         /* If we knew for certain that this is arithmetic for an array
-            reference, and we knew the bounds of the array, then we could
-            apply the distributive law across (PLUS X C) for constant C.
-            Without such knowledge, we risk overflowing the computation
-            when both X and C are large, but X+C isn't.  */
-         /* ??? Could perhaps special-case EXP being unsigned and C being
-            positive.  In that case we are certain that X+C is no smaller
-            than X and so the transformed expression will overflow iff the
-            original would have.  */
-
-         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,
@@ -8304,9 +8002,6 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                                             TYPE_MODE (TREE_TYPE (exp1))));
        }
 
-      if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
-       subtarget = 0;
-
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
 
@@ -8327,39 +8022,43 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                   || 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)
                {
-                 op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
-                                    NULL_RTX, VOIDmode, 0);
                  if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
-                   op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
-                                      VOIDmode, 0);
+                   expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
+                                    TREE_OPERAND (exp, 1),
+                                    NULL_RTX, &op0, &op1, 0);
                  else
-                   op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
-                                      NULL_RTX, VOIDmode, 0);
+                   expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
+                                    TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
+                                    NULL_RTX, &op0, &op1, 0);
                  goto binop2;
                }
              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)
@@ -8372,22 +8071,18 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                                       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;
                }
            }
        }
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      if (! operand_equal_p (TREE_OPERAND (exp, 0),
-                            TREE_OPERAND (exp, 1), 0))
-       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
-      else
-       op1 = op0;
+      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                      subtarget, &op0, &op1, 0);
       return expand_mult (mode, op0, op1, target, unsignedp);
 
     case TRUNC_DIV_EXPR:
@@ -8395,15 +8090,13 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
     case CEIL_DIV_EXPR:
     case ROUND_DIV_EXPR:
     case EXACT_DIV_EXPR:
-      if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
-       subtarget = 0;
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
       /* Possible optimization: compute the dividend with EXPAND_SUM
         then if the divisor is constant can optimize the case
         where some terms of the dividend have coeffs divisible by it.  */
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
+      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                      subtarget, &op0, &op1, 0);
       return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
 
     case RDIV_EXPR:
@@ -8425,12 +8118,10 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
     case FLOOR_MOD_EXPR:
     case CEIL_MOD_EXPR:
     case ROUND_MOD_EXPR:
-      if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
-       subtarget = 0;
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
+      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                      subtarget, &op0, &op1, 0);
       return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
 
     case FIX_ROUND_EXPR:
@@ -8455,7 +8146,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        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:
@@ -8482,7 +8173,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
 
       /* 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,
@@ -8493,19 +8184,18 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       target = original_target;
       if (target == 0
          || modifier == EXPAND_STACK_PARM
-         || ! safe_from_p (target, TREE_OPERAND (exp, 1), 1)
          || (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);
-      op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
-      op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
+      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                      target, &op0, &op1, 0);
 
       /* 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));
 
@@ -8520,6 +8210,14 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       if (GET_CODE (target) == MEM)
        target = gen_reg_rtx (mode);
 
+      /* If op1 was placed in target, swap op0 and op1.  */
+      if (target != op0 && target == op1)
+       {
+         rtx tem = op0;
+         op0 = op1;
+         op1 = tem;
+       }
+
       if (target != op0)
        emit_move_insn (target, op0);
 
@@ -8531,18 +8229,16 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          && ! 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);
@@ -8557,43 +8253,6 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        abort ();
       return temp;
 
-    case FFS_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      if (modifier == EXPAND_STACK_PARM)
-       target = 0;
-      temp = expand_unop (mode, ffs_optab, op0, target, 1);
-      if (temp == 0)
-       abort ();
-      return temp;
-
-    case CLZ_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      temp = expand_unop (mode, clz_optab, op0, target, 1);
-      if (temp == 0)
-       abort ();
-      return temp;
-
-    case CTZ_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      temp = expand_unop (mode, ctz_optab, op0, target, 1);
-      if (temp == 0)
-       abort ();
-      return temp;
-
-    case POPCOUNT_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      temp = expand_unop (mode, popcount_optab, op0, target, 1);
-      if (temp == 0)
-       abort ();
-      return temp;
-
-    case PARITY_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      temp = expand_unop (mode, parity_optab, op0, target, 1);
-      if (temp == 0)
-       abort ();
-      return temp;
-
       /* ??? Can optimize bitwise operations with one arg constant.
         Can optimize (a bitwise1 n) bitwise2 (a bitwise3 b)
         and (a bitwise1 b) bitwise2 b (etc)
@@ -8649,6 +8308,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
     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);
@@ -8658,7 +8318,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       /* 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)))))
        {
@@ -8705,7 +8365,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
              || ! 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);
 
@@ -8736,11 +8396,81 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
     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
@@ -8837,13 +8567,13 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          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
@@ -8919,7 +8649,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                   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,
@@ -8962,7 +8692,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                     || 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,
@@ -8970,8 +8700,12 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
            jumpif (TREE_OPERAND (exp, 0), op0);
 
            start_cleanup_deferral ();
-           store_expr (TREE_OPERAND (exp, 2), temp,
-                       modifier == EXPAND_STACK_PARM ? 2 : 0);
+           if (TREE_TYPE (TREE_OPERAND (exp, 2)) != void_type_node)
+             store_expr (TREE_OPERAND (exp, 2), temp,
+                         modifier == EXPAND_STACK_PARM ? 2 : 0);
+           else
+             expand_expr (TREE_OPERAND (exp, 2),
+                          ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
            op1 = op0;
          }
        else if (temp
@@ -8983,7 +8717,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                     || 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,
@@ -8991,8 +8725,12 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
            jumpifnot (TREE_OPERAND (exp, 0), op0);
 
            start_cleanup_deferral ();
-           store_expr (TREE_OPERAND (exp, 1), temp,
-                       modifier == EXPAND_STACK_PARM ? 2 : 0);
+           if (TREE_TYPE (TREE_OPERAND (exp, 1)) != void_type_node)
+             store_expr (TREE_OPERAND (exp, 1), temp,
+                         modifier == EXPAND_STACK_PARM ? 2 : 0);
+           else
+             expand_expr (TREE_OPERAND (exp, 1),
+                          ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
            op1 = op0;
          }
        else
@@ -9074,8 +8812,6 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
            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);
@@ -9089,7 +8825,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
 
                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);
              }
          }
@@ -9125,7 +8861,12 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        /* 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));
 
@@ -9212,18 +8953,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
     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
@@ -9259,7 +8991,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          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)
            {
@@ -9297,11 +9029,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
            {
              op0 = XEXP (op0, 0);
-#ifdef POINTERS_EXTEND_UNSIGNED
-             if (GET_MODE (op0) == Pmode && GET_MODE (op0) != mode
-                 && mode == ptr_mode)
+             if (GET_MODE (op0) == Pmode && mode == ptr_mode)
                op0 = convert_memory_address (ptr_mode, op0);
-#endif
              return op0;
            }
 
@@ -9352,21 +9081,18 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        }
 
       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)));
 
-#ifdef POINTERS_EXTEND_UNSIGNED
-      if (GET_MODE (op0) == Pmode && GET_MODE (op0) != mode
-         && mode == ptr_mode)
+      if (GET_MODE (op0) == Pmode && mode == ptr_mode)
        op0 = convert_memory_address (ptr_mode, op0);
-#endif
 
       return op0;
 
@@ -9456,25 +9182,38 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        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.
@@ -9543,22 +9282,109 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
     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
      from the optab already placed in `this_optab'.  */
  binop:
-  if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
-    subtarget = 0;
-  op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-  op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
+  expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                  subtarget, &op0, &op1, 0);
  binop2:
   if (modifier == EXPAND_STACK_PARM)
     target = 0;
@@ -9576,18 +9402,18 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
 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;
 
@@ -9608,13 +9434,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
@@ -9633,6 +9454,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);
@@ -9728,7 +9556,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);
 
@@ -9799,7 +9627,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.  */
 
@@ -9852,7 +9680,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)
@@ -9912,7 +9740,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.  */
@@ -9996,6 +9824,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 ();
@@ -10021,9 +9852,9 @@ 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), 
+                                               arg0, arg1, type),
                          target, VOIDmode, EXPAND_NORMAL);
     }
 
@@ -10053,12 +9884,10 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
     }
 
   if (! get_subtarget (target)
-      || GET_MODE (subtarget) != operand_mode
-      || ! safe_from_p (subtarget, arg1, 1))
+      || GET_MODE (subtarget) != operand_mode)
     subtarget = 0;
 
-  op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
-  op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+  expand_operands (arg0, arg1, subtarget, &op0, &op1, 0);
 
   if (target == 0)
     target = gen_reg_rtx (mode);
@@ -10081,7 +9910,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));
 
@@ -10167,7 +9996,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);
        }
@@ -10187,7 +10016,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);
@@ -10196,7 +10025,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);
@@ -10248,11 +10077,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
 
@@ -10310,7 +10139,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;
 }
@@ -10355,7 +10184,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);
@@ -10383,5 +10212,4 @@ const_vector_from_tree (tree exp)
 
   return gen_rtx_raw_CONST_VECTOR (mode, v);
 }
-
 #include "gt-expr.h"