OSDN Git Service

Add CONST1_RTX (vector mode) support.
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index b7f71c6..44f485b 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,19 +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
-#define TARGET_MEM_FUNCTIONS 1
-#else
-#define TARGET_MEM_FUNCTIONS 0
-#endif
-
 
 /* If this is nonzero, we do not bother generating VOLATILE
    around volatile memory references, and we are willing to
@@ -94,9 +86,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
@@ -130,13 +119,13 @@ struct store_by_pieces
   int reverse;
 };
 
-static rtx enqueue_insn (rtx, rtx);
 static unsigned HOST_WIDE_INT move_by_pieces_ninsns (unsigned HOST_WIDE_INT,
+                                                    unsigned int,
                                                     unsigned int);
 static void move_by_pieces_1 (rtx (*) (rtx, ...), enum machine_mode,
                              struct move_by_pieces *);
 static bool block_move_libcall_safe_for_call_parm (void);
-static bool emit_block_move_via_movstr (rtx, rtx, rtx, unsigned);
+static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned);
 static rtx emit_block_move_via_libcall (rtx, rtx, rtx);
 static tree emit_block_move_libcall_fn (int);
 static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned);
@@ -145,25 +134,25 @@ static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int);
 static void store_by_pieces_1 (struct store_by_pieces *, unsigned int);
 static void store_by_pieces_2 (rtx (*) (rtx, ...), enum machine_mode,
                               struct store_by_pieces *);
-static bool clear_storage_via_clrstr (rtx, rtx, unsigned);
+static bool clear_storage_via_clrmem (rtx, rtx, unsigned);
 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);
 static void store_constructor (tree, rtx, int, HOST_WIDE_INT);
 static rtx store_field (rtx, HOST_WIDE_INT, HOST_WIDE_INT, enum machine_mode,
                        tree, enum machine_mode, int, tree, int);
-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 reduce_to_bit_field_precision (rtx, rtx, tree);
 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,56 +171,41 @@ 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
 #define MOVE_BY_PIECES_P(SIZE, ALIGN) \
-  (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
+  (move_by_pieces_ninsns (SIZE, ALIGN, MOVE_MAX_PIECES + 1) \
+   < (unsigned int) MOVE_RATIO)
 #endif
 
 /* This macro is used to determine whether clear_by_pieces should be
    called to clear storage.  */
 #ifndef CLEAR_BY_PIECES_P
 #define CLEAR_BY_PIECES_P(SIZE, ALIGN) \
-  (move_by_pieces_ninsns (SIZE, ALIGN) < (unsigned int) CLEAR_RATIO)
+  (move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
+   < (unsigned int) CLEAR_RATIO)
 #endif
 
 /* This macro is used to determine whether store_by_pieces should be
    called to "memset" storage with byte values other than zero, or
    to "memcpy" storage when the source is a constant string.  */
 #ifndef STORE_BY_PIECES_P
-#define STORE_BY_PIECES_P(SIZE, ALIGN) MOVE_BY_PIECES_P (SIZE, ALIGN)
+#define STORE_BY_PIECES_P(SIZE, ALIGN) \
+  (move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
+   < (unsigned int) MOVE_RATIO)
 #endif
 
 /* This array records the insn_code of insns to perform block moves.  */
-enum insn_code movstr_optab[NUM_MACHINE_MODES];
+enum insn_code movmem_optab[NUM_MACHINE_MODES];
 
 /* This array records the insn_code of insns to perform block clears.  */
-enum insn_code clrstr_optab[NUM_MACHINE_MODES];
+enum insn_code clrmem_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.  */
 
@@ -338,198 +312,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;
-}
-
-/* Small sanity check that the queue is empty at the end of a function.  */
-
-void
-finish_expr_for_function (void)
-{
-  if (pending_chain)
-    abort ();
-}
-\f
-/* Manage the queue of increment instructions to be output
-   for POSTINCREMENT_EXPR expressions, etc.  */
-
-/* Queue up to increment (or change) VAR later.  BODY says how:
-   BODY should be the same thing you would pass to emit_insn
-   to increment right away.  It will go to emit_insn later on.
-
-   The value is a QUEUED expression to be used in place of VAR
-   where you want to guarantee the pre-incrementation value of VAR.  */
-
-static rtx
-enqueue_insn (rtx var, rtx body)
-{
-  pending_chain = gen_rtx_QUEUED (GET_MODE (var), var, NULL_RTX, NULL_RTX,
-                                 body, pending_chain);
-  return pending_chain;
-}
-
-/* Use protect_from_queue to convert a QUEUED expression
-   into something that you can put immediately into an instruction.
-   If the queued incrementation has not happened yet,
-   protect_from_queue returns the variable itself.
-   If the incrementation has happened, protect_from_queue returns a temp
-   that contains a copy of the old value of the variable.
-
-   Any time an rtx which might possibly be a QUEUED is to be put
-   into an instruction, it must be passed through protect_from_queue first.
-   QUEUED expressions are not meaningful in instructions.
-
-   Do not pass a value through protect_from_queue and then hold
-   on to it for a while before putting it in an instruction!
-   If the queue is flushed in between, incorrect code will result.  */
-
-rtx
-protect_from_queue (rtx x, int modify)
-{
-  RTX_CODE code = GET_CODE (x);
-
-#if 0  /* A QUEUED can hang around after the queue is forced out.  */
-  /* Shortcut for most common case.  */
-  if (pending_chain == 0)
-    return x;
-#endif
-
-  if (code != QUEUED)
-    {
-      /* A special hack for read access to (MEM (QUEUED ...)) to facilitate
-        use of autoincrement.  Make a copy of the contents of the memory
-        location rather than a copy of the address, but not if the value is
-        of mode BLKmode.  Don't modify X in place since it might be
-        shared.  */
-      if (code == MEM && GET_MODE (x) != BLKmode
-         && GET_CODE (XEXP (x, 0)) == QUEUED && !modify)
-       {
-         rtx y = XEXP (x, 0);
-         rtx new = replace_equiv_address_nv (x, QUEUED_VAR (y));
-
-         if (QUEUED_INSN (y))
-           {
-             rtx temp = gen_reg_rtx (GET_MODE (x));
-
-             emit_insn_before (gen_move_insn (temp, new),
-                               QUEUED_INSN (y));
-             return temp;
-           }
-
-         /* Copy the address into a pseudo, so that the returned value
-            remains correct across calls to emit_queue.  */
-         return replace_equiv_address (new, copy_to_reg (XEXP (new, 0)));
-       }
-
-      /* Otherwise, recursively protect the subexpressions of all
-        the kinds of rtx's that can contain a QUEUED.  */
-      if (code == MEM)
-       {
-         rtx tem = protect_from_queue (XEXP (x, 0), 0);
-         if (tem != XEXP (x, 0))
-           {
-             x = copy_rtx (x);
-             XEXP (x, 0) = tem;
-           }
-       }
-      else if (code == PLUS || code == MULT)
-       {
-         rtx new0 = protect_from_queue (XEXP (x, 0), 0);
-         rtx new1 = protect_from_queue (XEXP (x, 1), 0);
-         if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
-           {
-             x = copy_rtx (x);
-             XEXP (x, 0) = new0;
-             XEXP (x, 1) = new1;
-           }
-       }
-      return x;
-    }
-  /* If the increment has not happened, use the variable itself.  Copy it
-     into a new pseudo so that the value remains correct across calls to
-     emit_queue.  */
-  if (QUEUED_INSN (x) == 0)
-    return copy_to_reg (QUEUED_VAR (x));
-  /* If the increment has happened and a pre-increment copy exists,
-     use that copy.  */
-  if (QUEUED_COPY (x) != 0)
-    return QUEUED_COPY (x);
-  /* The increment has happened but we haven't set up a pre-increment copy.
-     Set one up now, and use it.  */
-  QUEUED_COPY (x) = gen_reg_rtx (GET_MODE (QUEUED_VAR (x)));
-  emit_insn_before (gen_move_insn (QUEUED_COPY (x), QUEUED_VAR (x)),
-                   QUEUED_INSN (x));
-  return QUEUED_COPY (x);
-}
-
-/* Return nonzero if X contains a QUEUED expression:
-   if it contains anything that will be altered by a queued increment.
-   We handle only combinations of MEM, PLUS, MINUS and MULT operators
-   since memory addresses generally contain only those.  */
-
-int
-queued_subexp_p (rtx x)
-{
-  enum rtx_code code = GET_CODE (x);
-  switch (code)
-    {
-    case QUEUED:
-      return 1;
-    case MEM:
-      return queued_subexp_p (XEXP (x, 0));
-    case MULT:
-    case PLUS:
-    case MINUS:
-      return (queued_subexp_p (XEXP (x, 0))
-             || queued_subexp_p (XEXP (x, 1)));
-    default:
-      return 0;
-    }
-}
-
-/* Perform all the pending incrementations.  */
-
-void
-emit_queue (void)
-{
-  rtx p;
-  while ((p = pending_chain))
-    {
-      rtx body = QUEUED_BODY (p);
-
-      switch (GET_CODE (body))
-       {
-       case INSN:
-       case JUMP_INSN:
-       case CALL_INSN:
-       case CODE_LABEL:
-       case BARRIER:
-       case NOTE:
-         QUEUED_INSN (p) = body;
-         emit_insn (body);
-         break;
-
-#ifdef ENABLE_CHECKING
-       case SEQUENCE:
-         abort ();
-         break;
-#endif
-
-       default:
-         QUEUED_INSN (p) = emit_insn (body);
-         break;
-       }
-
-      pending_chain = QUEUED_NEXT (p);
-    }
+  cfun->expr = ggc_alloc_cleared (sizeof (struct expr_status));
 }
 \f
 /* Copy data from FROM to TO, where the machine modes are not the same.
@@ -551,11 +334,13 @@ convert_move (rtx to, rtx from, int unsignedp)
   enum rtx_code equiv_code = (unsignedp < 0 ? UNKNOWN
                              : (unsignedp ? ZERO_EXTEND : SIGN_EXTEND));
 
-  to = protect_from_queue (to, 1);
-  from = protect_from_queue (from, 0);
 
-  if (to_real != from_real)
-    abort ();
+  gcc_assert (to_real == from_real);
+
+  /* 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
@@ -567,8 +352,7 @@ convert_move (rtx to, rtx from, int unsignedp)
       && SUBREG_PROMOTED_UNSIGNED_P (from) == unsignedp)
     from = gen_lowpart (to_mode, from), from_mode = to_mode;
 
-  if (GET_CODE (to) == SUBREG && SUBREG_PROMOTED_VAR_P (to))
-    abort ();
+  gcc_assert (GET_CODE (to) != SUBREG || !SUBREG_PROMOTED_VAR_P (to));
 
   if (to_mode == from_mode
       || (from_mode == VOIDmode && CONSTANT_P (from)))
@@ -579,8 +363,7 @@ convert_move (rtx to, rtx from, int unsignedp)
 
   if (VECTOR_MODE_P (to_mode) || VECTOR_MODE_P (from_mode))
     {
-      if (GET_MODE_BITSIZE (from_mode) != GET_MODE_BITSIZE (to_mode))
-       abort ();
+      gcc_assert (GET_MODE_BITSIZE (from_mode) == GET_MODE_BITSIZE (to_mode));
 
       if (VECTOR_MODE_P (to_mode))
        from = simplify_gen_subreg (to_mode, from, GET_MODE (from), 0);
@@ -598,260 +381,80 @@ 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
+      gcc_assert (GET_MODE_PRECISION (from_mode)
+                 != GET_MODE_PRECISION (to_mode));
+      
+      if (GET_MODE_PRECISION (from_mode) < GET_MODE_PRECISION (to_mode))
+       tab = sext_optab;
+      else
+       tab = trunc_optab;
 
-#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;
+      /* Otherwise use a libcall.  */
+      libcall = tab->handlers[to_mode][from_mode].libfunc;
 
-       case TFmode:
-         switch (to_mode)
-           {
-           case SFmode:
-             libcall = trunctfsf2_libfunc;
-             break;
-
-           case DFmode:
-             libcall = trunctfdf2_libfunc;
-             break;
-
-           default:
-             break;
-           }
-         break;
-
-       default:
-         break;
-       }
-
-      if (libcall == (rtx) 0)
-       /* This conversion is not implemented yet.  */
-       abort ();
+      /* Is this conversion implemented yet?  */
+      gcc_assert (libcall);
 
       start_sequence ();
       value = emit_library_call_value (libcall, NULL_RTX, LCT_CONST, to_mode,
                                       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);
+
+      gcc_assert (trunc_optab->handlers[to_mode][full_mode].insn_code
+                 != CODE_FOR_nothing);
+
+      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);
+
+      gcc_assert (sext_optab->handlers[full_mode][from_mode].insn_code
+                 != CODE_FOR_nothing);
+
+      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.  */
 
@@ -885,8 +488,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);
@@ -945,8 +552,7 @@ convert_move (rtx to, rtx from, int unsignedp)
          int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i);
          rtx subword = operand_subword (to, index, 1, to_mode);
 
-         if (subword == 0)
-           abort ();
+         gcc_assert (subword);
 
          if (fill_value != subword)
            emit_move_insn (subword, fill_value);
@@ -964,146 +570,33 @@ convert_move (rtx to, rtx from, int unsignedp)
   if (GET_MODE_BITSIZE (from_mode) > BITS_PER_WORD
       && GET_MODE_BITSIZE (to_mode) <= BITS_PER_WORD)
     {
-      if (!((GET_CODE (from) == MEM
+      if (!((MEM_P (from)
             && ! 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 ();
-    }
+  /* Now follow all the conversions between integers
+     no more than a word long.  */
 
-  if (from_mode == PQImode)
+  /* For truncation, usually we can just refer to FROM in a narrower mode.  */
+  if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode)
+      && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (to_mode),
+                               GET_MODE_BITSIZE (from_mode)))
     {
-      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.  */
-
-  /* For truncation, usually we can just refer to FROM in a narrower mode.  */
-  if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode)
-      && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (to_mode),
-                               GET_MODE_BITSIZE (from_mode)))
-    {
-      if (!((GET_CODE (from) == MEM
+      if (!((MEM_P (from)
             && ! 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));
@@ -1147,8 +640,9 @@ 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);
+         shift_amount = build_int_cst (NULL_TREE,
+                                       GET_MODE_BITSIZE (to_mode)
+                                       - GET_MODE_BITSIZE (from_mode));
          from = gen_lowpart (to_mode, force_reg (from_mode, from));
          tmp = expand_shift (LSHIFT_EXPR, to_mode, from, shift_amount,
                              to, unsignedp);
@@ -1161,140 +655,20 @@ convert_move (rtx to, rtx from, int unsignedp)
     }
 
   /* 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)
+  if (trunc_optab->handlers[to_mode][from_mode].insn_code != CODE_FOR_nothing)
     {
-#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);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
-
-  if (from_mode == TImode && to_mode == QImode)
-    {
-#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));
@@ -1303,7 +677,7 @@ convert_move (rtx to, rtx from, int unsignedp)
     }
 
   /* Mode combination is not recognized.  */
-  abort ();
+  gcc_unreachable ();
 }
 
 /* Return an rtx for a value that would result
@@ -1311,10 +685,7 @@ convert_move (rtx to, rtx from, int unsignedp)
    Both X and MODE may be floating, or both integer.
    UNSIGNEDP is nonzero if X is an unsigned value.
    This can be done by referring to a part of X in place
-   or by copying to a new temporary with conversion.
-
-   This function *must not* call protect_from_queue
-   except when putting X into an insn (in which case convert_move does it).  */
+   or by copying to a new temporary with conversion.  */
 
 rtx
 convert_to_mode (enum machine_mode mode, rtx x, int unsignedp)
@@ -1330,10 +701,7 @@ convert_to_mode (enum machine_mode mode, rtx x, int unsignedp)
    This can be done by referring to a part of X in place
    or by copying to a new temporary with conversion.
 
-   You can give VOIDmode for OLDMODE, if you are sure X has a nonvoid mode.
-
-   This function *must not* call protect_from_queue
-   except when putting X into an insn (in which case convert_move does it).  */
+   You can give VOIDmode for OLDMODE, if you are sure X has a nonvoid mode.  */
 
 rtx
 convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int unsignedp)
@@ -1389,9 +757,9 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
          && GET_MODE_CLASS (oldmode) == MODE_INT
          && (GET_CODE (x) == CONST_DOUBLE
              || (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (oldmode)
-                 && ((GET_CODE (x) == MEM && ! MEM_VOLATILE_P (x)
+                 && ((MEM_P (x) && ! 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),
@@ -1423,8 +791,7 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
      subreg operation.  */
   if (VECTOR_MODE_P (mode) && GET_MODE (x) == VOIDmode)
     {
-      if (GET_MODE_BITSIZE (mode) != GET_MODE_BITSIZE (oldmode))
-       abort ();
+      gcc_assert (GET_MODE_BITSIZE (mode) == GET_MODE_BITSIZE (oldmode));
       return simplify_gen_subreg (mode, x, oldmode, 0);
     }
 
@@ -1452,8 +819,7 @@ can_move_by_pieces (unsigned HOST_WIDE_INT len,
 }
 
 /* Generate several move instructions to copy LEN bytes from block FROM to
-   block TO.  (These are MEM rtx's with BLKmode).  The caller must pass FROM
-   and TO through protect_from_queue before calling.
+   block TO.  (These are MEM rtx's with BLKmode).
 
    If PUSH_ROUNDING is defined and TO is NULL, emit_single_push_insn is
    used to push FROM to the stack.
@@ -1515,7 +881,7 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
      copy addresses to registers (to make displacements shorter)
      and use post-increment if available.  */
   if (!(data.autinc_from && data.autinc_to)
-      && move_by_pieces_ninsns (len, align) > 2)
+      && move_by_pieces_ninsns (len, align, max_size) > 2)
     {
       /* Find the mode of the largest move...  */
       for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
@@ -1553,9 +919,22 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
        data.to_addr = copy_addr_to_reg (to_addr);
     }
 
-  if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
-      || align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
-    align = MOVE_MAX * BITS_PER_UNIT;
+  tmode = mode_for_size (MOVE_MAX_PIECES * BITS_PER_UNIT, MODE_INT, 1);
+  if (align >= GET_MODE_ALIGNMENT (tmode))
+    align = GET_MODE_ALIGNMENT (tmode);
+  else
+    {
+      enum machine_mode xmode;
+
+      for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT), xmode = tmode;
+          tmode != VOIDmode;
+          xmode = tmode, tmode = GET_MODE_WIDER_MODE (tmode))
+       if (GET_MODE_SIZE (tmode) > MOVE_MAX_PIECES
+           || SLOW_UNALIGNED_ACCESS (tmode, align))
+         break;
+
+      align = MAX (align, GET_MODE_ALIGNMENT (xmode));
+    }
 
   /* First move what we can in the largest integer mode, then go to
      successively smaller modes.  */
@@ -1578,15 +957,13 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
     }
 
   /* The code above should have handled everything.  */
-  if (data.len > 0)
-    abort ();
+  gcc_assert (!data.len);
 
   if (endp)
     {
       rtx to1;
 
-      if (data.reverse)
-       abort ();
+      gcc_assert (!data.reverse);
       if (data.autinc_to)
        {
          if (endp == 2)
@@ -1616,18 +993,32 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
    ALIGN (in bits) is maximum alignment we can assume.  */
 
 static unsigned HOST_WIDE_INT
-move_by_pieces_ninsns (unsigned HOST_WIDE_INT l, unsigned int align)
+move_by_pieces_ninsns (unsigned HOST_WIDE_INT l, unsigned int align,
+                      unsigned int max_size)
 {
   unsigned HOST_WIDE_INT n_insns = 0;
-  unsigned HOST_WIDE_INT max_size = MOVE_MAX + 1;
+  enum machine_mode tmode;
+
+  tmode = mode_for_size (MOVE_MAX_PIECES * BITS_PER_UNIT, MODE_INT, 1);
+  if (align >= GET_MODE_ALIGNMENT (tmode))
+    align = GET_MODE_ALIGNMENT (tmode);
+  else
+    {
+      enum machine_mode tmode, xmode;
+
+      for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT), xmode = tmode;
+          tmode != VOIDmode;
+          xmode = tmode, tmode = GET_MODE_WIDER_MODE (tmode))
+       if (GET_MODE_SIZE (tmode) > MOVE_MAX_PIECES
+           || SLOW_UNALIGNED_ACCESS (tmode, align))
+         break;
 
-  if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
-      || align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
-    align = MOVE_MAX * BITS_PER_UNIT;
+      align = MAX (align, GET_MODE_ALIGNMENT (xmode));
+    }
 
   while (max_size > 1)
     {
-      enum machine_mode mode = VOIDmode, tmode;
+      enum machine_mode mode = VOIDmode;
       enum insn_code icode;
 
       for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
@@ -1645,8 +1036,7 @@ move_by_pieces_ninsns (unsigned HOST_WIDE_INT l, unsigned int align)
       max_size = GET_MODE_SIZE (mode);
     }
 
-  if (l)
-    abort ();
+  gcc_assert (!l);
   return n_insns;
 }
 
@@ -1695,7 +1085,7 @@ move_by_pieces_1 (rtx (*genfun) (rtx, ...), enum machine_mode mode,
 #ifdef PUSH_ROUNDING
          emit_single_push_insn (mode, from1, NULL);
 #else
-         abort ();
+         gcc_unreachable ();
 #endif
        }
 
@@ -1749,26 +1139,19 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   align = MIN (MEM_ALIGN (x), MEM_ALIGN (y));
 
-  if (GET_MODE (x) != BLKmode)
-    abort ();
-  if (GET_MODE (y) != BLKmode)
-    abort ();
+  gcc_assert (MEM_P (x));
+  gcc_assert (MEM_P (y));
+  gcc_assert (size);
 
-  x = protect_from_queue (x, 1);
-  y = protect_from_queue (y, 0);
-  size = protect_from_queue (size, 0);
-
-  if (GET_CODE (x) != MEM)
-    abort ();
-  if (GET_CODE (y) != MEM)
-    abort ();
-  if (size == 0)
-    abort ();
+  /* Make sure we've got BLKmode addresses; store_one_arg can decide that
+     block copy is more efficient for other large modes, e.g. DCmode.  */
+  x = adjust_address (x, BLKmode, 0);
+  y = adjust_address (y, BLKmode, 0);
 
   /* Set MEM_SIZE as appropriate for this block copy.  The main place this
      can be incorrect is coming from __builtin_memcpy.  */
@@ -1785,7 +1168,7 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
 
   if (GET_CODE (size) == CONST_INT && MOVE_BY_PIECES_P (INTVAL (size), align))
     move_by_pieces (x, y, INTVAL (size), align, 0);
-  else if (emit_block_move_via_movstr (x, y, size, align))
+  else if (emit_block_move_via_movmem (x, y, size, align))
     ;
   else if (may_use_call)
     retval = emit_block_move_via_libcall (x, y, size);
@@ -1805,65 +1188,54 @@ 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;
+       if (FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode,
+                                       NULL_TREE, 1))
+         return false;
+       FUNCTION_ARG_ADVANCE (args_so_far, mode, NULL_TREE, 1);
+      }
+  }
+  return true;
 }
 
-/* A subroutine of emit_block_move.  Expand a movstr pattern;
+/* A subroutine of emit_block_move.  Expand a movmem pattern;
    return true if successful.  */
 
 static bool
-emit_block_move_via_movstr (rtx x, rtx y, rtx size, unsigned int align)
+emit_block_move_via_movmem (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.  */
@@ -1876,7 +1248,7 @@ emit_block_move_via_movstr (rtx x, rtx y, rtx size, unsigned int align)
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     {
-      enum insn_code code = movstr_optab[(int) mode];
+      enum insn_code code = movmem_optab[(int) mode];
       insn_operand_predicate_fn pred;
 
       if (code != CODE_FOR_nothing
@@ -1913,7 +1285,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
@@ -1921,11 +1293,11 @@ emit_block_move_via_movstr (rtx x, rtx y, rtx size, unsigned int align)
        }
     }
 
-  volatile_ok = 0;
+  volatile_ok = save_volatile_ok;
   return false;
 }
 
-/* A subroutine of emit_block_move.  Expand a call to memcpy or bcopy.
+/* A subroutine of emit_block_move.  Expand a call to memcpy.
    Return the return value from memcpy, 0 otherwise.  */
 
 static rtx
@@ -1936,42 +1308,20 @@ emit_block_move_via_libcall (rtx dst, rtx src, rtx size)
   enum machine_mode size_mode;
   rtx retval;
 
-  /* DST, SRC, or SIZE may have been passed through protect_from_queue.
-
-     It is unsafe to save the value generated by protect_from_queue and reuse
-     it later.  Consider what happens if emit_queue is called before the
-     return value from protect_from_queue is used.
-
-     Expansion of the CALL_EXPR below will call emit_queue before we are
-     finished emitting RTL for argument setup.  So if we are not careful we
-     could get the wrong value for an argument.
-
-     To avoid this problem we go ahead and emit code to copy the addresses of
-     DST and SRC and SIZE into new pseudos.  We can then place those new
-     pseudos into an RTL_EXPR and use them later, even after a call to
-     emit_queue.
-
-     Note this is not strictly needed for library calls since they do not call
-     emit_queue before loading their arguments.  However, we may need to have
-     library calls call emit_queue in the future since failing to do so could
-     cause problems for targets which define SMALL_REGISTER_CLASSES and pass
-     arguments in registers.  */
+  /* Emit code to copy the addresses of DST and SRC and SIZE into new
+     pseudos.  We can then place those new pseudos into a VAR_DECL and
+     use them later.  */
 
   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);
 
-  if (TARGET_MEM_FUNCTIONS)
-    size_mode = TYPE_MODE (sizetype);
-  else
-    size_mode = TYPE_MODE (unsigned_type_node);
+  size_mode = TYPE_MODE (sizetype);
 
   size = convert_to_mode (size_mode, size, 1);
   size = copy_to_mode_reg (size_mode, size);
@@ -1980,47 +1330,23 @@ emit_block_move_via_libcall (rtx dst, rtx src, rtx size)
      memcpy in this context.  This could be a user call to memcpy and
      the user may wish to examine the return value from memcpy.  For
      targets where libcalls and normal calls have different conventions
-     for returning pointers, we could end up generating incorrect code.
-
-     For convenience, we generate the call to bcopy this way as well.  */
+     for returning pointers, we could end up generating incorrect code.  */
 
-  if (TARGET_MEM_FUNCTIONS)
-    size_tree = make_tree (sizetype, size);
-  else
-    size_tree = make_tree (unsigned_type_node, size);
+  size_tree = make_tree (sizetype, size);
 
   fn = emit_block_move_libcall_fn (true);
   arg_list = tree_cons (NULL_TREE, size_tree, NULL_TREE);
-  if (TARGET_MEM_FUNCTIONS)
-    {
-      arg_list = tree_cons (NULL_TREE, src_tree, arg_list);
-      arg_list = tree_cons (NULL_TREE, dst_tree, arg_list);
-    }
-  else
-    {
-      arg_list = tree_cons (NULL_TREE, dst_tree, arg_list);
-      arg_list = tree_cons (NULL_TREE, src_tree, arg_list);
-    }
+  arg_list = tree_cons (NULL_TREE, src_tree, arg_list);
+  arg_list = tree_cons (NULL_TREE, dst_tree, arg_list);
 
   /* Now we have to build up the CALL_EXPR itself.  */
   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;
+  call_expr = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+                     call_expr, arg_list, NULL_TREE);
 
   retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
 
-  /* If we are initializing a readonly value, show the above call clobbered
-     it. Otherwise, a load from it may erroneously be hoisted from a loop, or
-     the delay slot scheduler might overlook conflicts and take nasty
-     decisions.  */
-  if (RTX_UNCHANGING_P (dst))
-    add_function_usage_to
-      (last_call_insn (), gen_rtx_EXPR_LIST (VOIDmode,
-                                            gen_rtx_CLOBBER (VOIDmode, dst),
-                                            NULL_RTX));
-
-  return TARGET_MEM_FUNCTIONS ? retval : NULL_RTX;
+  return retval;
 }
 
 /* A subroutine of emit_block_move_via_libcall.  Create the tree node
@@ -2036,20 +1362,10 @@ init_block_move_fn (const char *asmspec)
     {
       tree args, fn;
 
-      if (TARGET_MEM_FUNCTIONS)
-       {
-         fn = get_identifier ("memcpy");
-         args = build_function_type_list (ptr_type_node, ptr_type_node,
-                                          const_ptr_type_node, sizetype,
-                                          NULL_TREE);
-       }
-      else
-       {
-         fn = get_identifier ("bcopy");
-         args = build_function_type_list (void_type_node, const_ptr_type_node,
-                                          ptr_type_node, unsigned_type_node,
-                                          NULL_TREE);
-       }
+      fn = get_identifier ("memcpy");
+      args = build_function_type_list (ptr_type_node, ptr_type_node,
+                                      const_ptr_type_node, sizetype,
+                                      NULL_TREE);
 
       fn = build_decl (FUNCTION_DECL, fn, args);
       DECL_EXTERNAL (fn) = 1;
@@ -2061,10 +1377,7 @@ init_block_move_fn (const char *asmspec)
     }
 
   if (asmspec)
-    {
-      SET_DECL_RTL (block_move_fn, NULL_RTX);
-      SET_DECL_ASSEMBLER_NAME (block_move_fn, get_identifier (asmspec));
-    }
+    set_user_assembler_name (block_move_fn, asmspec);
 }
 
 static tree
@@ -2078,7 +1391,7 @@ emit_block_move_libcall_fn (int for_call)
   if (for_call && !emitted_extern)
     {
       emitted_extern = true;
-      make_decl_rtl (block_move_fn, NULL);
+      make_decl_rtl (block_move_fn);
       assemble_external (block_move_fn);
     }
 
@@ -2110,8 +1423,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);
 
@@ -2128,13 +1439,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.
@@ -2209,8 +1517,7 @@ move_block_from_reg (int regno, rtx x, int nregs)
     {
       rtx tem = operand_subword (x, i, 1, BLKmode);
 
-      if (tem == 0)
-       abort ();
+      gcc_assert (tem);
 
       emit_move_insn (tem, gen_rtx_REG (word_mode, regno + i));
     }
@@ -2228,8 +1535,7 @@ gen_group_rtx (rtx orig)
   int i, length;
   rtx *tmps;
 
-  if (GET_CODE (orig) != PARALLEL)
-    abort ();
+  gcc_assert (GET_CODE (orig) == PARALLEL);
 
   length = XVECLEN (orig, 0);
   tmps = alloca (sizeof (rtx) * length);
@@ -2254,7 +1560,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)
@@ -2262,8 +1568,7 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
   rtx *tmps, src;
   int start, i;
 
-  if (GET_CODE (dst) != PARALLEL)
-    abort ();
+  gcc_assert (GET_CODE (dst) == PARALLEL);
 
   /* Check for a NULL entry, used to indicate that the parameter goes
      both on the stack and in registers.  */
@@ -2297,15 +1602,14 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
              )
            shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
          bytelen = ssize - bytepos;
-         if (bytelen <= 0)
-           abort ();
+         gcc_assert (bytelen > 0);
        }
 
       /* If we won't be loading directly from memory, protect the real source
         from strange tricks we might play; but make sure that the source can
         be loaded directly into the destination.  */
       src = orig_src;
-      if (GET_CODE (orig_src) != MEM
+      if (!MEM_P (orig_src)
          && (!CONSTANT_P (orig_src)
              || (GET_MODE (orig_src) != mode
                  && GET_MODE (orig_src) != VOIDmode)))
@@ -2319,7 +1623,7 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
        }
 
       /* Optimize the access just a bit.  */
-      if (GET_CODE (src) == MEM
+      if (MEM_P (src)
          && (! SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (src))
              || MEM_ALIGN (src) >= GET_MODE_ALIGNMENT (mode))
          && bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
@@ -2342,25 +1646,26 @@ 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);
+                                            1, NULL_RTX, mode, mode);
            }
-         else if (bytepos == 0)
+         else
            {
-             rtx mem = assign_stack_temp (GET_MODE (src), slen, 0);
+             rtx mem;
+             
+             gcc_assert (!bytepos);
+             mem = assign_stack_temp (GET_MODE (src), slen, 0);
              emit_move_insn (mem, src);
              tmps[i] = adjust_address (mem, mode, 0);
            }
-         else
-           abort ();
        }
       /* FIXME: A SIMD parallel will eventually lead to a subreg of a
         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;
@@ -2369,21 +1674,22 @@ 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,
                                     bytepos * BITS_PER_UNIT, 1, NULL_RTX,
-                                    mode, mode, ssize);
+                                    mode, mode);
 
       if (shift)
-       expand_binop (mode, ashl_optab, tmps[i], GEN_INT (shift),
-                     tmps[i], 0, OPTAB_WIDEN);
+       tmps[i] = expand_shift (LSHIFT_EXPR, mode, tmps[i],
+                               build_int_cst (NULL_TREE, shift), tmps[i], 0);
     }
 
-  emit_queue ();
-
   /* Copy the extracted pieces into the proper (probable) hard regs.  */
   for (i = start; i < XVECLEN (dst, 0); i++)
     emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
@@ -2397,10 +1703,9 @@ emit_group_move (rtx dst, rtx src)
 {
   int i;
 
-  if (GET_CODE (src) != PARALLEL
-      || GET_CODE (dst) != PARALLEL
-      || XVECLEN (src, 0) != XVECLEN (dst, 0))
-    abort ();
+  gcc_assert (GET_CODE (src) == PARALLEL
+             && GET_CODE (dst) == PARALLEL
+             && XVECLEN (src, 0) == XVECLEN (dst, 0));
 
   /* Skip first entry if NULL.  */
   for (i = XEXP (XVECEXP (src, 0, 0), 0) ? 0 : 1; i < XVECLEN (src, 0); i++)
@@ -2419,8 +1724,7 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
   rtx *tmps, dst;
   int start, i;
 
-  if (GET_CODE (src) != PARALLEL)
-    abort ();
+  gcc_assert (GET_CODE (src) == PARALLEL);
 
   /* Check for a NULL entry, used to indicate that the parameter goes
      both on the stack and in registers.  */
@@ -2438,7 +1742,6 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
       tmps[i] = gen_reg_rtx (GET_MODE (reg));
       emit_move_insn (tmps[i], reg);
     }
-  emit_queue ();
 
   /* If we won't be storing directly into memory, protect the real destination
      from strange tricks we might play.  */
@@ -2462,7 +1765,7 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
       emit_group_load (dst, temp, type, ssize);
       return;
     }
-  else if (GET_CODE (dst) != MEM && GET_CODE (dst) != CONCAT)
+  else if (!MEM_P (dst) && GET_CODE (dst) != CONCAT)
     {
       dst = gen_reg_rtx (GET_MODE (orig_dst));
       /* Make life a bit easier for combine.  */
@@ -2492,8 +1795,9 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
              )
            {
              int shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
-             expand_binop (mode, ashr_optab, tmps[i], GEN_INT (shift),
-                           tmps[i], 0, OPTAB_WIDEN);
+             tmps[i] = expand_shift (RSHIFT_EXPR, mode, tmps[i],
+                                     build_int_cst (NULL_TREE, shift),
+                                     tmps[i], 0);
            }
          bytelen = ssize - bytepos;
        }
@@ -2507,8 +1811,9 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
              bytepos -= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0)));
              dest = XEXP (dst, 1);
            }
-         else if (bytepos == 0 && XVECLEN (src, 0))
+         else
            {
+             gcc_assert (bytepos == 0 && XVECLEN (src, 0));
              dest = assign_stack_temp (GET_MODE (dest),
                                        GET_MODE_SIZE (GET_MODE (dest)), 0);
              emit_move_insn (adjust_address (dest, GET_MODE (tmps[i]), bytepos),
@@ -2516,12 +1821,10 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
              dst = dest;
              break;
            }
-         else
-           abort ();
        }
 
       /* Optimize the access just a bit.  */
-      if (GET_CODE (dest) == MEM
+      if (MEM_P (dest)
          && (! SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (dest))
              || MEM_ALIGN (dest) >= GET_MODE_ALIGNMENT (mode))
          && bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
@@ -2529,11 +1832,9 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
        emit_move_insn (adjust_address (dest, mode, bytepos), tmps[i]);
       else
        store_bit_field (dest, bytelen * BITS_PER_UNIT, bytepos * BITS_PER_UNIT,
-                        mode, tmps[i], ssize);
+                        mode, tmps[i]);
     }
 
-  emit_queue ();
-
   /* Copy from the pseudo into the (probable) hard reg.  */
   if (orig_dst != dst)
     emit_move_insn (orig_dst, dst);
@@ -2543,10 +1844,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)
@@ -2554,7 +1855,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)
     {
@@ -2570,15 +1871,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.
@@ -2586,15 +1894,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));
 
@@ -2608,9 +1916,7 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
       store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, word_mode,
                       extract_bit_field (src, bitsize,
                                          xbitpos % BITS_PER_WORD, 1,
-                                         NULL_RTX, word_mode, word_mode,
-                                         BITS_PER_WORD),
-                      BITS_PER_WORD);
+                                         NULL_RTX, word_mode, word_mode));
     }
 
   return tgtblk;
@@ -2622,10 +1928,8 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
 void
 use_reg (rtx *call_fusage, rtx reg)
 {
-  if (GET_CODE (reg) != REG
-      || REGNO (reg) >= FIRST_PSEUDO_REGISTER)
-    abort ();
-
+  gcc_assert (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER);
+  
   *call_fusage
     = gen_rtx_EXPR_LIST (VOIDmode,
                         gen_rtx_USE (VOIDmode, reg), *call_fusage);
@@ -2639,8 +1943,7 @@ use_regs (rtx *call_fusage, int regno, int nregs)
 {
   int i;
 
-  if (regno + nregs > FIRST_PSEUDO_REGISTER)
-    abort ();
+  gcc_assert (regno + nregs <= FIRST_PSEUDO_REGISTER);
 
   for (i = 0; i < nregs; i++)
     use_reg (call_fusage, regno_reg_rtx[regno + i]);
@@ -2662,7 +1965,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);
     }
 }
@@ -2679,7 +1982,8 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
                     rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
                     void *constfundata, unsigned int align)
 {
-  unsigned HOST_WIDE_INT max_size, l;
+  unsigned HOST_WIDE_INT l;
+  unsigned int max_size;
   HOST_WIDE_INT offset = 0;
   enum machine_mode mode, tmode;
   enum insn_code icode;
@@ -2692,9 +1996,22 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
   if (! STORE_BY_PIECES_P (len, align))
     return 0;
 
-  if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
-      || align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
-    align = MOVE_MAX * BITS_PER_UNIT;
+  tmode = mode_for_size (STORE_MAX_PIECES * BITS_PER_UNIT, MODE_INT, 1);
+  if (align >= GET_MODE_ALIGNMENT (tmode))
+    align = GET_MODE_ALIGNMENT (tmode);
+  else
+    {
+      enum machine_mode xmode;
+
+      for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT), xmode = tmode;
+          tmode != VOIDmode;
+          xmode = tmode, tmode = GET_MODE_WIDER_MODE (tmode))
+       if (GET_MODE_SIZE (tmode) > STORE_MAX_PIECES
+           || SLOW_UNALIGNED_ACCESS (tmode, align))
+         break;
+
+      align = MAX (align, GET_MODE_ALIGNMENT (xmode));
+    }
 
   /* We would first store what we can in the largest integer mode, then go to
      successively smaller modes.  */
@@ -2742,8 +2059,7 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
        }
 
       /* The code above should have handled everything.  */
-      if (l != 0)
-       abort ();
+      gcc_assert (!l);
     }
 
   return 1;
@@ -2766,14 +2082,11 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
 
   if (len == 0)
     {
-      if (endp == 2)
-       abort ();
+      gcc_assert (endp != 2);
       return to;
     }
 
-  if (! STORE_BY_PIECES_P (len, align))
-    abort ();
-  to = protect_from_queue (to, 1);
+  gcc_assert (STORE_BY_PIECES_P (len, align));
   data.constfun = constfun;
   data.constfundata = constfundata;
   data.len = len;
@@ -2783,8 +2096,7 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
     {
       rtx to1;
 
-      if (data.reverse)
-       abort ();
+      gcc_assert (!data.reverse);
       if (data.autinc_to)
        {
          if (endp == 2)
@@ -2811,8 +2123,7 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
 }
 
 /* Generate several move instructions to clear LEN bytes of block TO.  (A MEM
-   rtx with BLKmode).  The caller must pass TO through protect_from_queue
-   before calling. ALIGN is maximum alignment we can assume.  */
+   rtx with BLKmode).  ALIGN is maximum alignment we can assume.  */
 
 static void
 clear_by_pieces (rtx to, unsigned HOST_WIDE_INT len, unsigned int align)
@@ -2842,15 +2153,14 @@ clear_by_pieces_1 (void *data ATTRIBUTE_UNUSED,
 
 /* Subroutine of clear_by_pieces and store_by_pieces.
    Generate several move instructions to store LEN bytes of block TO.  (A MEM
-   rtx with BLKmode).  The caller must pass TO through protect_from_queue
-   before calling.  ALIGN is maximum alignment we can assume.  */
+   rtx with BLKmode).  ALIGN is maximum alignment we can assume.  */
 
 static void
 store_by_pieces_1 (struct store_by_pieces *data ATTRIBUTE_UNUSED,
                   unsigned int align ATTRIBUTE_UNUSED)
 {
   rtx to_addr = XEXP (data->to, 0);
-  unsigned HOST_WIDE_INT max_size = STORE_MAX_PIECES + 1;
+  unsigned int max_size = STORE_MAX_PIECES + 1;
   enum machine_mode mode = VOIDmode, tmode;
   enum insn_code icode;
 
@@ -2870,7 +2180,7 @@ store_by_pieces_1 (struct store_by_pieces *data ATTRIBUTE_UNUSED,
      copy addresses to registers (to make displacements shorter)
      and use post-increment if available.  */
   if (!data->autinc_to
-      && move_by_pieces_ninsns (data->len, align) > 2)
+      && move_by_pieces_ninsns (data->len, align, max_size) > 2)
     {
       /* Determine the main mode we'll be using.  */
       for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
@@ -2897,9 +2207,22 @@ store_by_pieces_1 (struct store_by_pieces *data ATTRIBUTE_UNUSED,
        data->to_addr = copy_addr_to_reg (to_addr);
     }
 
-  if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
-      || align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
-    align = MOVE_MAX * BITS_PER_UNIT;
+  tmode = mode_for_size (STORE_MAX_PIECES * BITS_PER_UNIT, MODE_INT, 1);
+  if (align >= GET_MODE_ALIGNMENT (tmode))
+    align = GET_MODE_ALIGNMENT (tmode);
+  else
+    {
+      enum machine_mode xmode;
+
+      for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT), xmode = tmode;
+          tmode != VOIDmode;
+          xmode = tmode, tmode = GET_MODE_WIDER_MODE (tmode))
+       if (GET_MODE_SIZE (tmode) > STORE_MAX_PIECES
+           || SLOW_UNALIGNED_ACCESS (tmode, align))
+         break;
+
+      align = MAX (align, GET_MODE_ALIGNMENT (xmode));
+    }
 
   /* First store what we can in the largest integer mode, then go to
      successively smaller modes.  */
@@ -2922,8 +2245,7 @@ store_by_pieces_1 (struct store_by_pieces *data ATTRIBUTE_UNUSED,
     }
 
   /* The code above should have handled everything.  */
-  if (data->len != 0)
-    abort ();
+  gcc_assert (!data->len);
 }
 
 /* Subroutine of store_by_pieces_1.  Store as many bytes as appropriate
@@ -2972,7 +2294,7 @@ rtx
 clear_storage (rtx object, rtx size)
 {
   rtx retval = 0;
-  unsigned int align = (GET_CODE (object) == MEM ? MEM_ALIGN (object)
+  unsigned int align = (MEM_P (object) ? MEM_ALIGN (object)
                        : GET_MODE_ALIGNMENT (GET_MODE (object)));
 
   /* If OBJECT is not BLKmode and SIZE is the same size as its mode,
@@ -2983,15 +2305,12 @@ clear_storage (rtx object, rtx size)
     emit_move_insn (object, CONST0_RTX (GET_MODE (object)));
   else
     {
-      object = protect_from_queue (object, 1);
-      size = protect_from_queue (size, 0);
-
       if (size == const0_rtx)
        ;
       else if (GET_CODE (size) == CONST_INT
          && CLEAR_BY_PIECES_P (INTVAL (size), align))
        clear_by_pieces (object, INTVAL (size), align);
-      else if (clear_storage_via_clrstr (object, size, align))
+      else if (clear_storage_via_clrmem (object, size, align))
        ;
       else
        retval = clear_storage_via_libcall (object, size);
@@ -3000,11 +2319,11 @@ clear_storage (rtx object, rtx size)
   return retval;
 }
 
-/* A subroutine of clear_storage.  Expand a clrstr pattern;
+/* A subroutine of clear_storage.  Expand a clrmem pattern;
    return true if successful.  */
 
 static bool
-clear_storage_via_clrstr (rtx object, rtx size, unsigned int align)
+clear_storage_via_clrmem (rtx object, rtx size, unsigned int align)
 {
   /* Try the most limited insn first, because there's no point
      including more than one in the machine description unless
@@ -3016,7 +2335,7 @@ clear_storage_via_clrstr (rtx object, rtx size, unsigned int align)
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     {
-      enum insn_code code = clrstr_optab[(int) mode];
+      enum insn_code code = clrmem_optab[(int) mode];
       insn_operand_predicate_fn pred;
 
       if (code != CODE_FOR_nothing
@@ -3056,7 +2375,7 @@ clear_storage_via_clrstr (rtx object, rtx size, unsigned int align)
   return false;
 }
 
-/* A subroutine of clear_storage.  Expand a call to memset or bzero.
+/* A subroutine of clear_storage.  Expand a call to memset.
    Return the return value of memset, 0 otherwise.  */
 
 static rtx
@@ -3066,33 +2385,12 @@ clear_storage_via_libcall (rtx object, rtx size)
   enum machine_mode size_mode;
   rtx retval;
 
-  /* OBJECT or SIZE may have been passed through protect_from_queue.
-
-     It is unsafe to save the value generated by protect_from_queue
-     and reuse it later.  Consider what happens if emit_queue is
-     called before the return value from protect_from_queue is used.
-
-     Expansion of the CALL_EXPR below will call emit_queue before
-     we are finished emitting RTL for argument setup.  So if we are
-     not careful we could get the wrong value for an argument.
-
-     To avoid this problem we go ahead and emit code to copy OBJECT
-     and SIZE into new pseudos.  We can then place those new pseudos
-     into an RTL_EXPR and use them later, even after a call to
-     emit_queue.
-
-     Note this is not strictly needed for library calls since they
-     do not call emit_queue before loading their arguments.  However,
-     we may need to have library calls call emit_queue in the future
-     since failing to do so could cause problems for targets which
-     define SMALL_REGISTER_CLASSES and pass arguments in registers.  */
+  /* Emit code to copy OBJECT and SIZE into new pseudos.  We can then
+     place those into new pseudos into a VAR_DECL and use them later.  */
 
   object = copy_to_mode_reg (Pmode, XEXP (object, 0));
 
-  if (TARGET_MEM_FUNCTIONS)
-    size_mode = TYPE_MODE (sizetype);
-  else
-    size_mode = TYPE_MODE (unsigned_type_node);
+  size_mode = TYPE_MODE (sizetype);
   size = convert_to_mode (size_mode, size, 1);
   size = copy_to_mode_reg (size_mode, size);
 
@@ -3100,37 +2398,24 @@ clear_storage_via_libcall (rtx object, rtx size)
      memset in this context.  This could be a user call to memset and
      the user may wish to examine the return value from memset.  For
      targets where libcalls and normal calls have different conventions
-     for returning pointers, we could end up generating incorrect code.
-
-     For convenience, we generate the call to bzero this way as well.  */
+     for returning pointers, we could end up generating incorrect code.  */
 
   object_tree = make_tree (ptr_type_node, object);
-  if (TARGET_MEM_FUNCTIONS)
-    size_tree = make_tree (sizetype, size);
-  else
-    size_tree = make_tree (unsigned_type_node, size);
+  size_tree = make_tree (sizetype, size);
 
   fn = clear_storage_libcall_fn (true);
   arg_list = tree_cons (NULL_TREE, size_tree, NULL_TREE);
-  if (TARGET_MEM_FUNCTIONS)
-    arg_list = tree_cons (NULL_TREE, integer_zero_node, arg_list);
+  arg_list = tree_cons (NULL_TREE, integer_zero_node, arg_list);
   arg_list = tree_cons (NULL_TREE, object_tree, arg_list);
 
   /* Now we have to build up the CALL_EXPR itself.  */
   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;
+  call_expr = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+                     call_expr, arg_list, NULL_TREE);
 
   retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
 
-  /* If we are initializing a readonly value, show the above call
-     clobbered it.  Otherwise, a load from it may erroneously be
-     hoisted from a loop.  */
-  if (RTX_UNCHANGING_P (object))
-    emit_insn (gen_rtx_CLOBBER (VOIDmode, object));
-
-  return (TARGET_MEM_FUNCTIONS ? retval : NULL_RTX);
+  return retval;
 }
 
 /* A subroutine of clear_storage_via_libcall.  Create the tree node
@@ -3146,19 +2431,10 @@ init_block_clear_fn (const char *asmspec)
     {
       tree fn, args;
 
-      if (TARGET_MEM_FUNCTIONS)
-       {
-         fn = get_identifier ("memset");
-         args = build_function_type_list (ptr_type_node, ptr_type_node,
-                                          integer_type_node, sizetype,
-                                          NULL_TREE);
-       }
-      else
-       {
-         fn = get_identifier ("bzero");
-         args = build_function_type_list (void_type_node, ptr_type_node,
-                                          unsigned_type_node, NULL_TREE);
-       }
+      fn = get_identifier ("memset");
+      args = build_function_type_list (ptr_type_node, ptr_type_node,
+                                      integer_type_node, sizetype,
+                                      NULL_TREE);
 
       fn = build_decl (FUNCTION_DECL, fn, args);
       DECL_EXTERNAL (fn) = 1;
@@ -3170,10 +2446,7 @@ init_block_clear_fn (const char *asmspec)
     }
 
   if (asmspec)
-    {
-      SET_DECL_RTL (block_clear_fn, NULL_RTX);
-      SET_DECL_ASSEMBLER_NAME (block_clear_fn, get_identifier (asmspec));
-    }
+    set_user_assembler_name (block_clear_fn, asmspec);
 }
 
 static tree
@@ -3187,7 +2460,7 @@ clear_storage_libcall_fn (int for_call)
   if (for_call && !emitted_extern)
     {
       emitted_extern = true;
-      make_decl_rtl (block_clear_fn, NULL);
+      make_decl_rtl (block_clear_fn);
       assemble_external (block_clear_fn);
     }
 
@@ -3208,16 +2481,10 @@ emit_move_insn (rtx x, rtx y)
   rtx y_cst = NULL_RTX;
   rtx last_insn, set;
 
-  x = protect_from_queue (x, 1);
-  y = protect_from_queue (y, 0);
-
-  if (mode == BLKmode || (GET_MODE (y) != mode && GET_MODE (y) != VOIDmode))
-    abort ();
+  gcc_assert (mode != BLKmode
+             && (GET_MODE (y) == mode || GET_MODE (y) == VOIDmode));
 
-  /* 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))
@@ -3240,25 +2507,24 @@ emit_move_insn (rtx x, rtx y)
 
   /* If X or Y are memory references, verify that their addresses are valid
      for the machine.  */
-  if (GET_CODE (x) == MEM
+  if (MEM_P (x)
       && ((! memory_address_p (GET_MODE (x), XEXP (x, 0))
           && ! push_operand (x, GET_MODE (x)))
          || (flag_force_addr
              && CONSTANT_ADDRESS_P (XEXP (x, 0)))))
     x = validize_mem (x);
 
-  if (GET_CODE (y) == MEM
+  if (MEM_P (y)
       && (! memory_address_p (GET_MODE (y), XEXP (y, 0))
          || (flag_force_addr
              && CONSTANT_ADDRESS_P (XEXP (y, 0)))))
     y = validize_mem (y);
 
-  if (mode == BLKmode)
-    abort ();
+  gcc_assert (mode != BLKmode);
 
   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)))
@@ -3278,8 +2544,7 @@ emit_move_insn_1 (rtx x, rtx y)
   enum machine_mode submode;
   enum mode_class class = GET_MODE_CLASS (mode);
 
-  if ((unsigned int) mode >= (unsigned int) MAX_MACHINE_MODE)
-    abort ();
+  gcc_assert ((unsigned int) mode < (unsigned int) MAX_MACHINE_MODE);
 
   if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
     return
@@ -3400,9 +2665,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);
@@ -3462,8 +2724,7 @@ emit_move_insn_1 (rtx x, rtx y)
          if (GET_MODE_SIZE (tmode) == GET_MODE_SIZE (mode))
            break;
 
-      if (tmode == VOIDmode)
-       abort ();
+      gcc_assert (tmode != VOIDmode);
 
       /* Get X and Y in TMODE.  We can't use gen_lowpart here because it
         may call change_address which is not appropriate if we were
@@ -3475,14 +2736,14 @@ emit_move_insn_1 (rtx x, rtx y)
       if (reload_in_progress)
        {
          x = gen_lowpart_common (tmode, x1);
-         if (x == 0 && GET_CODE (x1) == MEM)
+         if (x == 0 && MEM_P (x1))
            {
              x = adjust_address_nv (x1, tmode, 0);
              copy_replacements (x1, x);
            }
 
          y = gen_lowpart_common (tmode, y1);
-         if (y == 0 && GET_CODE (y1) == MEM)
+         if (y == 0 && MEM_P (y1))
            {
              y = adjust_address_nv (y1, tmode, 0);
              copy_replacements (y1, y);
@@ -3498,16 +2759,29 @@ 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.  */
-  else if (GET_MODE_SIZE (mode) >= UNITS_PER_WORD)
+  else
     {
       rtx last_insn = 0;
       rtx seq, inner;
       int need_clobber;
       int i;
-
+      
+      gcc_assert (GET_MODE_SIZE (mode) >= UNITS_PER_WORD);
+      
 #ifdef PUSH_ROUNDING
 
       /* If X is a push on the stack, do the push now and replace
@@ -3553,10 +2827,10 @@ emit_move_insn_1 (rtx x, rtx y)
 
       /* If we are in reload, see if either operand is a MEM whose address
         is scheduled for replacement.  */
-      if (reload_in_progress && GET_CODE (x) == MEM
+      if (reload_in_progress && MEM_P (x)
          && (inner = find_replacement (&XEXP (x, 0))) != XEXP (x, 0))
        x = replace_equiv_address_nv (x, inner);
-      if (reload_in_progress && GET_CODE (y) == MEM
+      if (reload_in_progress && MEM_P (y)
          && (inner = find_replacement (&XEXP (y, 0))) != XEXP (y, 0))
        y = replace_equiv_address_nv (y, inner);
 
@@ -3581,8 +2855,7 @@ emit_move_insn_1 (rtx x, rtx y)
          else if (ypart == 0)
            ypart = operand_subword_force (y, i, mode);
 
-         if (xpart == 0 || ypart == 0)
-           abort ();
+         gcc_assert (xpart && ypart);
 
          need_clobber |= (GET_CODE (xpart) == SUBREG);
 
@@ -3605,8 +2878,6 @@ emit_move_insn_1 (rtx x, rtx y)
 
       return last_insn;
     }
-  else
-    abort ();
 }
 
 /* If Y is representable exactly in a narrower mode, and the target can
@@ -3656,7 +2927,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;
@@ -3669,7 +2940,6 @@ compress_float_constant (rtx x, rtx y)
 
 /* Push a block of length SIZE (perhaps variable)
    and return an rtx to address the beginning of the block.
-   Note that it is not possible for the value returned to be a QUEUED.
    The value may be virtual_outgoing_args_rtx.
 
    EXTRA is the number of bytes of padding to push in addition to SIZE.
@@ -3684,7 +2954,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
     {
@@ -3870,7 +3140,7 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
     if (where_pad != none)
       where_pad = (where_pad == downward ? upward : downward);
 
-  xinner = x = protect_from_queue (x, 0);
+  xinner = x;
 
   if (mode == BLKmode)
     {
@@ -3878,11 +3148,20 @@ 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 (size == 0)
-       abort ();
+      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);
+
+      gcc_assert (size);
 
       used -= offset;
 
@@ -3977,16 +3256,11 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
 
          target = gen_rtx_MEM (BLKmode, temp);
 
-         if (type != 0)
-           {
-             set_mem_attributes (target, type, 1);
-             /* Function incoming arguments may overlap with sibling call
-                outgoing arguments and we cannot allow reordering of reads
-                from function arguments with stores to outgoing arguments
-                of sibling calls.  */
-             set_mem_alias_set (target, 0);
-           }
-
+         /* We do *not* set_mem_attributes here, because incoming arguments
+            may overlap with sibling call outgoing arguments and we cannot
+            allow reordering of reads from function arguments with stores
+            to outgoing arguments of sibling calls.  We do, however, want
+            to record the alignment of the stack slot.  */
          /* ALIGN may well be better aligned than TYPE, e.g. due to
             PARM_BOUNDARY.  Assume the caller isn't lying.  */
          set_mem_align (target, align);
@@ -4035,7 +3309,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);
 
@@ -4082,15 +3356,15 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
            addr = memory_address (mode, gen_rtx_PLUS (Pmode, args_addr,
                                                       args_so_far));
          dest = gen_rtx_MEM (mode, addr);
-         if (type != 0)
-           {
-             set_mem_attributes (dest, type, 1);
-             /* Function incoming arguments may overlap with sibling call
-                outgoing arguments and we cannot allow reordering of reads
-                from function arguments with stores to outgoing arguments
-                of sibling calls.  */
-             set_mem_alias_set (dest, 0);
-           }
+
+         /* We do *not* set_mem_attributes here, because incoming arguments
+            may overlap with sibling call outgoing arguments and we cannot
+            allow reordering of reads from function arguments with stores
+            to outgoing arguments of sibling calls.  We do, however, want
+            to record the alignment of the stack slot.  */
+         /* ALIGN may well be better aligned than TYPE, e.g. due to
+            PARM_BOUNDARY.  Assume the caller isn't lying.  */
+         set_mem_align (dest, align);
 
          emit_move_insn (dest, x);
        }
@@ -4122,23 +3396,18 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
 static rtx
 get_subtarget (rtx x)
 {
-  return ((x == 0
+  return (optimize
+          || x == 0
           /* Only registers can be subtargets.  */
-          || GET_CODE (x) != REG
-          /* If the register is readonly, it can't be set more than once.  */
-          || RTX_UNCHANGING_P (x)
+          || !REG_P (x)
           /* Don't use hard regs to avoid extending their life.  */
           || REGNO (x) < FIRST_PSEUDO_REGISTER
-          /* Avoid subtargets inside loops,
-             since they hide some invariant expressions.  */
-          || preserve_subexpressions_p ())
          ? 0 : x);
 }
 
 /* Expand an assignment that stores the value of FROM into TO.
    If WANT_VALUE is nonzero, return an rtx for the value of TO.
-   (This may contain a QUEUED rtx;
-   if the value is constant, this rtx is a constant.)
+   (If the value is constant, this rtx is a constant.)
    Otherwise, the returned value is NULL_RTX.  */
 
 rtx
@@ -4189,8 +3458,7 @@ expand_assignment (tree to, tree from, int want_value)
        {
          rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
 
-         if (GET_CODE (to_rtx) != MEM)
-           abort ();
+         gcc_assert (MEM_P (to_rtx));
 
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (offset_rtx) != Pmode)
@@ -4202,7 +3470,7 @@ expand_assignment (tree to, tree from, int want_value)
 
          /* A constant address in TO_RTX can have VOIDmode, we must not try
             to call force_reg for that case.  Avoid that case.  */
-         if (GET_CODE (to_rtx) == MEM
+         if (MEM_P (to_rtx)
              && GET_MODE (to_rtx) == BLKmode
              && GET_MODE (XEXP (to_rtx, 0)) != VOIDmode
              && bitsize > 0
@@ -4215,11 +3483,11 @@ 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)
+      if (MEM_P (to_rtx))
        {
          /* If the field is at offset zero, we could have been given the
             DECL_RTX of the parent struct.  Don't munge it.  */
@@ -4230,46 +3498,151 @@ expand_assignment (tree to, tree from, int want_value)
 
       /* Deal with volatile and readonly fields.  The former is only done
         for MEM.  Also set MEM_KEEP_ALIAS_SET_P if needed.  */
-      if (volatilep && GET_CODE (to_rtx) == MEM)
+      if (volatilep && MEM_P (to_rtx))
        {
          if (to_rtx == orig_to_rtx)
            to_rtx = copy_rtx (to_rtx);
          MEM_VOLATILE_P (to_rtx) = 1;
        }
 
-      if (TREE_CODE (to) == COMPONENT_REF
-         && TREE_READONLY (TREE_OPERAND (to, 1)))
+      if (MEM_P (to_rtx) && ! can_address_p (to))
        {
          if (to_rtx == orig_to_rtx)
            to_rtx = copy_rtx (to_rtx);
-         RTX_UNCHANGING_P (to_rtx) = 1;
+         MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
        }
 
-      if (GET_CODE (to_rtx) == MEM && ! can_address_p (to))
+      /* Optimize bitfld op= val in certain cases.  */
+      while (mode1 == VOIDmode && !want_value
+            && bitsize > 0 && bitsize < BITS_PER_WORD
+            && GET_MODE_BITSIZE (GET_MODE (to_rtx)) <= BITS_PER_WORD
+            && !TREE_SIDE_EFFECTS (to)
+            && !TREE_THIS_VOLATILE (to))
        {
-         if (to_rtx == orig_to_rtx)
-           to_rtx = copy_rtx (to_rtx);
-         MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
-       }
+         tree src, op0, op1;
+         rtx value, str_rtx = to_rtx;
+         HOST_WIDE_INT bitpos1 = bitpos;
+         optab binop;
 
-      result = store_field (to_rtx, bitsize, bitpos, mode1, from,
-                           (want_value
-                            /* Spurious cast for HPUX compiler.  */
-                            ? ((enum machine_mode)
-                               TYPE_MODE (TREE_TYPE (to)))
-                            : VOIDmode),
-                           unsignedp, TREE_TYPE (tem), get_alias_set (to));
+         src = from;
+         STRIP_NOPS (src);
+         if (TREE_CODE (TREE_TYPE (src)) != INTEGER_TYPE
+             || TREE_CODE_CLASS (TREE_CODE (src)) != '2')
+           break;
 
-      preserve_temp_slots (result);
-      free_temp_slots ();
-      pop_temp_slots ();
+         op0 = TREE_OPERAND (src, 0);
+         op1 = TREE_OPERAND (src, 1);
+         STRIP_NOPS (op0);
+
+         if (! operand_equal_p (to, op0, 0))
+           break;
+
+         if (MEM_P (str_rtx))
+           {
+             enum machine_mode mode = GET_MODE (str_rtx);
+             HOST_WIDE_INT offset1;
+
+             if (GET_MODE_BITSIZE (mode) == 0
+                 || GET_MODE_BITSIZE (mode) > BITS_PER_WORD)
+               mode = word_mode;
+             mode = get_best_mode (bitsize, bitpos1, MEM_ALIGN (str_rtx),
+                                   mode, 0);
+             if (mode == VOIDmode)
+               break;
+
+             offset1 = bitpos1;
+             bitpos1 %= GET_MODE_BITSIZE (mode);
+             offset1 = (offset1 - bitpos1) / BITS_PER_UNIT;
+             str_rtx = adjust_address (str_rtx, mode, offset1);
+           }
+         else if (!REG_P (str_rtx) && GET_CODE (str_rtx) != SUBREG)
+           break;
+
+         /* If the bit field covers the whole REG/MEM, store_field
+            will likely generate better code.  */
+         if (bitsize >= GET_MODE_BITSIZE (GET_MODE (str_rtx)))
+           break;
+
+         /* We can't handle fields split across multiple entities.  */
+         if (bitpos1 + bitsize > GET_MODE_BITSIZE (GET_MODE (str_rtx)))
+           break;
+
+         if (BYTES_BIG_ENDIAN)
+           bitpos1 = GET_MODE_BITSIZE (GET_MODE (str_rtx)) - bitpos1
+                     - bitsize;
+
+         /* Special case some bitfield op= exp.  */
+         switch (TREE_CODE (src))
+           {
+           case PLUS_EXPR:
+           case MINUS_EXPR:
+             /* For now, just optimize the case of the topmost bitfield
+                where we don't need to do any masking and also
+                1 bit bitfields where xor can be used.
+                We might win by one instruction for the other bitfields
+                too if insv/extv instructions aren't used, so that
+                can be added later.  */
+             if (bitpos1 + bitsize != GET_MODE_BITSIZE (GET_MODE (str_rtx))
+                 && (bitsize != 1 || TREE_CODE (op1) != INTEGER_CST))
+               break;
+             value = expand_expr (op1, NULL_RTX, GET_MODE (str_rtx), 0);
+             value = convert_modes (GET_MODE (str_rtx),
+                                    TYPE_MODE (TREE_TYPE (op1)), value,
+                                    TYPE_UNSIGNED (TREE_TYPE (op1)));
+
+             /* We may be accessing data outside the field, which means
+                we can alias adjacent data.  */
+             if (MEM_P (str_rtx))
+               {
+                 str_rtx = shallow_copy_rtx (str_rtx);
+                 set_mem_alias_set (str_rtx, 0);
+                 set_mem_expr (str_rtx, 0);
+               }
+
+             binop = TREE_CODE (src) == PLUS_EXPR ? add_optab : sub_optab;
+             if (bitsize == 1
+                 && bitpos1 + bitsize != GET_MODE_BITSIZE (GET_MODE (str_rtx)))
+               {
+                 value = expand_and (GET_MODE (str_rtx), value, const1_rtx,
+                                     NULL_RTX);
+                 binop = xor_optab;
+               }
+             value = expand_shift (LSHIFT_EXPR, GET_MODE (str_rtx), value,
+                                   build_int_cst (NULL_TREE, bitpos1),
+                                   NULL_RTX, 1);
+             result = expand_binop (GET_MODE (str_rtx), binop, str_rtx,
+                                    value, str_rtx, 1, OPTAB_WIDEN);
+             if (result != str_rtx)
+               emit_move_insn (str_rtx, result);
+             free_temp_slots ();
+             pop_temp_slots ();
+             return NULL_RTX;
+
+           default:
+             break;
+           }
+
+         break;
+       }
+
+      result = store_field (to_rtx, bitsize, bitpos, mode1, from,
+                           (want_value
+                            /* Spurious cast for HPUX compiler.  */
+                            ? ((enum machine_mode)
+                               TYPE_MODE (TREE_TYPE (to)))
+                            : VOIDmode),
+                           unsignedp, TREE_TYPE (tem), get_alias_set (to));
+
+      preserve_temp_slots (result);
+      free_temp_slots ();
+      pop_temp_slots ();
 
       /* If the value is meaningful, convert RESULT to the proper mode.
         Otherwise, return nothing.  */
       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);
     }
 
@@ -4283,10 +3656,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;
 
@@ -4304,11 +3677,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);
@@ -4325,7 +3695,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;
 
@@ -4357,21 +3727,12 @@ expand_assignment (tree to, tree from, int want_value)
       size = expr_size (from);
       from_rtx = expand_expr (from, NULL_RTX, VOIDmode, 0);
 
-      if (TARGET_MEM_FUNCTIONS)
-       emit_library_call (memmove_libfunc, LCT_NORMAL,
-                          VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
-                          XEXP (from_rtx, 0), Pmode,
-                          convert_to_mode (TYPE_MODE (sizetype),
-                                           size, TREE_UNSIGNED (sizetype)),
-                          TYPE_MODE (sizetype));
-      else
-        emit_library_call (bcopy_libfunc, LCT_NORMAL,
-                          VOIDmode, 3, XEXP (from_rtx, 0), Pmode,
-                          XEXP (to_rtx, 0), Pmode,
-                          convert_to_mode (TYPE_MODE (integer_type_node),
-                                           size,
-                                           TREE_UNSIGNED (integer_type_node)),
-                          TYPE_MODE (integer_type_node));
+      emit_library_call (memmove_libfunc, LCT_NORMAL,
+                        VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
+                        XEXP (from_rtx, 0), Pmode,
+                        convert_to_mode (TYPE_MODE (sizetype),
+                                         size, TYPE_UNSIGNED (sizetype)),
+                        TYPE_MODE (sizetype));
 
       preserve_temp_slots (to_rtx);
       free_temp_slots ();
@@ -4391,7 +3752,6 @@ expand_assignment (tree to, tree from, int want_value)
 
 /* Generate code for computing expression EXP,
    and storing the value into TARGET.
-   TARGET may contain a QUEUED rtx.
 
    If WANT_VALUE & 1 is nonzero, return a copy of the value
    not in TARGET, so that we can be sure to use the proper
@@ -4419,6 +3779,7 @@ rtx
 store_expr (tree exp, rtx target, int want_value)
 {
   rtx temp;
+  rtx alt_rtl = NULL_RTX;
   int dont_return_target = 0;
   int dont_store_target = 0;
 
@@ -4427,8 +3788,7 @@ store_expr (tree exp, rtx target, int want_value)
       /* C++ can generate ?: expressions with a throw expression in one
         branch and an rvalue in the other. Here, we resolve attempts to
         store the throw expression's nonexistent result.  */
-      if (want_value)
-       abort ();
+      gcc_assert (!want_value);
       expand_expr (exp, const0_rtx, VOIDmode, 0);
       return NULL_RTX;
     }
@@ -4438,7 +3798,6 @@ store_expr (tree exp, rtx target, int want_value)
         part.  */
       expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
                   want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
-      emit_queue ();
       return store_expr (TREE_OPERAND (exp, 1), target, want_value);
     }
   else if (TREE_CODE (exp) == COND_EXPR && GET_MODE (target) == BLKmode)
@@ -4450,53 +3809,21 @@ store_expr (tree exp, rtx target, int want_value)
 
       rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
 
-      emit_queue ();
-      target = protect_from_queue (target, 1);
-
       do_pending_stack_adjust ();
       NO_DEFER_POP;
       jumpifnot (TREE_OPERAND (exp, 0), lab1);
-      start_cleanup_deferral ();
       store_expr (TREE_OPERAND (exp, 1), target, want_value & 2);
-      end_cleanup_deferral ();
-      emit_queue ();
       emit_jump_insn (gen_jump (lab2));
       emit_barrier ();
       emit_label (lab1);
-      start_cleanup_deferral ();
       store_expr (TREE_OPERAND (exp, 2), target, want_value & 2);
-      end_cleanup_deferral ();
-      emit_queue ();
       emit_label (lab2);
       OK_DEFER_POP;
 
       return want_value & 1 ? target : NULL_RTX;
     }
-  else if (queued_subexp_p (target))
-    /* If target contains a postincrement, let's not risk
-       using it as the place to generate the rhs.  */
-    {
-      if (GET_MODE (target) != BLKmode && GET_MODE (target) != VOIDmode)
-       {
-         /* Expand EXP into a new pseudo.  */
-         temp = gen_reg_rtx (GET_MODE (target));
-         temp = expand_expr (exp, temp, GET_MODE (target),
-                             (want_value & 2
-                              ? EXPAND_STACK_PARM : EXPAND_NORMAL));
-       }
-      else
-       temp = expand_expr (exp, NULL_RTX, GET_MODE (target),
-                           (want_value & 2
-                            ? EXPAND_STACK_PARM : EXPAND_NORMAL));
-
-      /* If target is volatile, ANSI requires accessing the value
-        *from* the target, if it is accessed.  So make that happen.
-        In no case return the target itself.  */
-      if (! MEM_VOLATILE_P (target) && (want_value & 1) != 0)
-       dont_return_target = 1;
-    }
   else if ((want_value & 1) != 0
-          && GET_CODE (target) == MEM
+          && MEM_P (target)
           && ! MEM_VOLATILE_P (target)
           && GET_MODE (target) != BLKmode)
     /* If target is in memory and caller wants value in a register instead,
@@ -4536,15 +3863,18 @@ store_expr (tree exp, rtx target, int want_value)
         more than just converting modes.  */
       if ((want_value & 1) == 0
          && INTEGRAL_TYPE_P (TREE_TYPE (exp))
-         && TREE_TYPE (TREE_TYPE (exp)) == 0)
+         && TREE_TYPE (TREE_TYPE (exp)) == 0
+         && (!lang_hooks.reduce_bit_field_operations
+             || (GET_MODE_PRECISION (GET_MODE (target))
+                 == TYPE_PRECISION (TREE_TYPE (exp)))))
        {
-         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);
@@ -4560,7 +3890,7 @@ store_expr (tree exp, rtx target, int want_value)
         only necessary if the MEM is volatile, or if the address
         overlaps TARGET.  But not performing the load twice also
         reduces the amount of rtl we generate and then have to CSE.  */
-      if (GET_CODE (temp) == MEM && (want_value & 1) != 0)
+      if (MEM_P (temp) && (want_value & 1) != 0)
        temp = copy_to_reg (temp);
 
       /* If TEMP is a VOIDmode constant, use convert_modes to make
@@ -4600,8 +3930,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.
@@ -4609,9 +3941,9 @@ 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))
+         && !(MEM_P (target) && MEM_VOLATILE_P (target))
          && ! rtx_equal_p (temp, target)
          && (CONSTANT_P (temp) || (want_value & 1) != 0))
        dont_return_target = 1;
@@ -4625,10 +3957,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:
@@ -4646,22 +3982,20 @@ 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)
     {
-      target = protect_from_queue (target, 1);
       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,
@@ -4702,7 +4036,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));
@@ -4724,7 +4058,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,
@@ -4751,7 +4085,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.  */
@@ -4760,13 +4098,13 @@ store_expr (tree exp, rtx target, int want_value)
 
   /* If we are supposed to return TEMP, do so as long as it isn't a MEM.
      ??? The latter test doesn't seem to make sense.  */
-  else if (dont_return_target && GET_CODE (temp) != MEM)
+  else if (dont_return_target && !MEM_P (temp))
     return temp;
 
   /* 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);
 
@@ -4774,50 +4112,165 @@ 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) + 1;
+           HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type));
+           if (n == 0)
+             return 0;
+           else 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:
+      return TYPE_VECTOR_SUBPARTS (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;
+      gcc_unreachable ();
     }
 }
 
@@ -4827,30 +4280,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;
 
-      return 4 * zeros >= 3 * elts;
+      categorize_ctor_elements (exp, &nz_elts, &nc_elts);
+      elts = count_type_elements (TREE_TYPE (exp));
+
+      return nz_elts < elts / 4;
     }
 
-  return is_zeros_p (exp);
+  return initializer_zerop (exp);
 }
 \f
 /* Helper function for store_constructor.
@@ -4870,13 +4314,16 @@ 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.  */
-      && (bitpos == 0 || GET_CODE (target) == MEM))
+      && (bitpos == 0 || MEM_P (target)))
     {
-      if (GET_CODE (target) == MEM)
+      if (MEM_P (target))
        target
          = adjust_address (target,
                            GET_MODE (target) == BLKmode
@@ -4886,7 +4333,7 @@ store_constructor_field (rtx target, unsigned HOST_WIDE_INT bitsize,
 
 
       /* Update the alias set, if required.  */
-      if (GET_CODE (target) == MEM && ! MEM_KEEP_ALIAS_SET_P (target)
+      if (MEM_P (target) && ! MEM_KEEP_ALIAS_SET_P (target)
          && MEM_ALIAS_SET (target) != 0)
        {
          target = copy_rtx (target);
@@ -4916,621 +4363,731 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
   HOST_WIDE_INT exp_size = int_size_in_bytes (type);
 #endif
 
-  if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
-      || TREE_CODE (type) == QUAL_UNION_TYPE)
+  switch (TREE_CODE (type))
     {
-      tree elt;
-
-      /* If size is zero or the target is already cleared, do nothing.  */
-      if (size == 0 || cleared)
-       cleared = 1;
-      /* We either clear the aggregate or indicate the value is dead.  */
-      else if ((TREE_CODE (type) == UNION_TYPE
-               || TREE_CODE (type) == QUAL_UNION_TYPE)
-              && ! CONSTRUCTOR_ELTS (exp))
-       /* If the constructor is empty, clear the union.  */
-       {
-         clear_storage (target, expr_size (exp));
-         cleared = 1;
-       }
-
-      /* If we are building a static constructor into a register,
-        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)
-              && GET_MODE_SIZE (GET_MODE (target)) <= UNITS_PER_WORD)
-       {
-         emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
-         cleared = 1;
-       }
-
-      /* If the constructor has fewer fields than the structure
-        or if we are initializing the structure to mostly zeros,
-        clear the whole structure first.  Don't do this 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
-                  || ((HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (target))
-                      == size)))
-       {
-         rtx xtarget = target;
-
-         if (readonly_fields_p (type))
-           {
-             xtarget = copy_rtx (xtarget);
-             RTX_UNCHANGING_P (xtarget) = 1;
-           }
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      {
+       tree elt;
 
-         clear_storage (xtarget, GEN_INT (size));
+       /* If size is zero or the target is already cleared, do nothing.  */
+       if (size == 0 || cleared)
          cleared = 1;
-       }
-
-      if (! cleared)
-       emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
-
-      /* Store each element of the constructor into
-        the corresponding field of TARGET.  */
-
-      for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
-       {
-         tree field = TREE_PURPOSE (elt);
-         tree value = TREE_VALUE (elt);
-         enum machine_mode mode;
-         HOST_WIDE_INT bitsize;
-         HOST_WIDE_INT bitpos = 0;
-         tree offset;
-         rtx to_rtx = target;
-
-         /* Just ignore missing fields.
-            We cleared the whole structure, above,
-            if any fields are missing.  */
-         if (field == 0)
-           continue;
-
-         if (cleared && is_zeros_p (value))
-           continue;
-
-         if (host_integerp (DECL_SIZE (field), 1))
-           bitsize = tree_low_cst (DECL_SIZE (field), 1);
-         else
-           bitsize = -1;
+       /* We either clear the aggregate or indicate the value is dead.  */
+       else if ((TREE_CODE (type) == UNION_TYPE
+                 || TREE_CODE (type) == QUAL_UNION_TYPE)
+                && ! CONSTRUCTOR_ELTS (exp))
+         /* If the constructor is empty, clear the union.  */
+         {
+           clear_storage (target, expr_size (exp));
+           cleared = 1;
+         }
 
-         mode = DECL_MODE (field);
-         if (DECL_BIT_FIELD (field))
-           mode = VOIDmode;
+       /* If we are building a static constructor into a register,
+          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 (REG_P (target) && TREE_STATIC (exp)
+                && GET_MODE_SIZE (GET_MODE (target)) <= UNITS_PER_WORD)
+         {
+           emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
+           cleared = 1;
+         }
 
-         offset = DECL_FIELD_OFFSET (field);
-         if (host_integerp (offset, 0)
-             && host_integerp (bit_position (field), 0))
-           {
-             bitpos = int_bit_position (field);
-             offset = 0;
-           }
-         else
-           bitpos = tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 0);
+        /* If the constructor has fewer fields than the structure or
+          if we are initializing the structure to mostly zeros, clear
+          the whole structure first.  Don't do this if TARGET is a
+          register whose mode size isn't equal to SIZE since
+          clear_storage can't handle this case.  */
+       else if (size > 0
+                && ((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)))
+         {
+           clear_storage (target, GEN_INT (size));
+           cleared = 1;
+         }
 
-         if (offset)
-           {
-             rtx offset_rtx;
+       if (! cleared)
+         emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
 
-             if (CONTAINS_PLACEHOLDER_P (offset))
-               offset = build (WITH_RECORD_EXPR, sizetype,
-                               offset, make_tree (TREE_TYPE (exp), target));
+       /* Store each element of the constructor into the
+          corresponding field of TARGET.  */
 
-             offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
-             if (GET_CODE (to_rtx) != MEM)
-               abort ();
+       for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
+         {
+           tree field = TREE_PURPOSE (elt);
+           tree value = TREE_VALUE (elt);
+           enum machine_mode mode;
+           HOST_WIDE_INT bitsize;
+           HOST_WIDE_INT bitpos = 0;
+           tree offset;
+           rtx to_rtx = target;
+           
+           /* Just ignore missing fields.  We cleared the whole
+              structure, above, if any fields are missing.  */
+           if (field == 0)
+             continue;
+           
+           if (cleared && initializer_zerop (value))
+             continue;
+           
+           if (host_integerp (DECL_SIZE (field), 1))
+             bitsize = tree_low_cst (DECL_SIZE (field), 1);
+           else
+             bitsize = -1;
+           
+           mode = DECL_MODE (field);
+           if (DECL_BIT_FIELD (field))
+             mode = VOIDmode;
+           
+           offset = DECL_FIELD_OFFSET (field);
+           if (host_integerp (offset, 0)
+               && host_integerp (bit_position (field), 0))
+             {
+               bitpos = int_bit_position (field);
+               offset = 0;
+             }
+           else
+             bitpos = tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 0);
+           
+           if (offset)
+             {
+               rtx offset_rtx;
+               
+               offset
+                 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (offset,
+                                                   make_tree (TREE_TYPE (exp),
+                                                              target));
 
+               offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
+               gcc_assert (MEM_P (to_rtx));
+               
 #ifdef POINTERS_EXTEND_UNSIGNED
-             if (GET_MODE (offset_rtx) != Pmode)
-               offset_rtx = convert_to_mode (Pmode, offset_rtx, 0);
+               if (GET_MODE (offset_rtx) != Pmode)
+                 offset_rtx = convert_to_mode (Pmode, offset_rtx, 0);
 #else
-             if (GET_MODE (offset_rtx) != ptr_mode)
-               offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
+               if (GET_MODE (offset_rtx) != ptr_mode)
+                 offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
 #endif
 
-             to_rtx = offset_address (to_rtx, offset_rtx,
-                                      highest_pow2_factor (offset));
-           }
-
-         if (TREE_READONLY (field))
-           {
-             if (GET_CODE (to_rtx) == MEM)
-               to_rtx = copy_rtx (to_rtx);
-
-             RTX_UNCHANGING_P (to_rtx) = 1;
-           }
+               to_rtx = offset_address (to_rtx, offset_rtx,
+                                        highest_pow2_factor (offset));
+             }
 
 #ifdef WORD_REGISTER_OPERATIONS
-         /* If this initializes a field that is smaller than a word, at the
-            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
-             && bitsize < BITS_PER_WORD
-             && bitpos % BITS_PER_WORD == 0
-             && GET_MODE_CLASS (mode) == MODE_INT
-             && TREE_CODE (value) == INTEGER_CST
-             && exp_size >= 0
-             && bitpos + BITS_PER_WORD <= exp_size * BITS_PER_UNIT)
-           {
-             tree type = TREE_TYPE (value);
-
-             if (TYPE_PRECISION (type) < BITS_PER_WORD)
-               {
-                 type = (*lang_hooks.types.type_for_size)
-                   (BITS_PER_WORD, TREE_UNSIGNED (type));
-                 value = convert (type, value);
-               }
-
-             if (BYTES_BIG_ENDIAN)
-               value
-                 = fold (build (LSHIFT_EXPR, type, value,
-                                build_int_2 (BITS_PER_WORD - bitsize, 0)));
-             bitsize = BITS_PER_WORD;
-             mode = word_mode;
-           }
+           /* If this initializes a field that is smaller than a
+              word, at the 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 (REG_P (target)
+               && bitsize < BITS_PER_WORD
+               && bitpos % BITS_PER_WORD == 0
+               && GET_MODE_CLASS (mode) == MODE_INT
+               && TREE_CODE (value) == INTEGER_CST
+               && exp_size >= 0
+               && bitpos + BITS_PER_WORD <= exp_size * BITS_PER_UNIT)
+             {
+               tree type = TREE_TYPE (value);
+               
+               if (TYPE_PRECISION (type) < BITS_PER_WORD)
+                 {
+                   type = lang_hooks.types.type_for_size
+                     (BITS_PER_WORD, TYPE_UNSIGNED (type));
+                   value = convert (type, value);
+                 }
+               
+               if (BYTES_BIG_ENDIAN)
+                 value
+                   = fold (build2 (LSHIFT_EXPR, type, value,
+                                   build_int_cst (NULL_TREE,
+                                                  BITS_PER_WORD - bitsize)));
+               bitsize = BITS_PER_WORD;
+               mode = word_mode;
+             }
 #endif
 
-         if (GET_CODE (to_rtx) == MEM && !MEM_KEEP_ALIAS_SET_P (to_rtx)
-             && DECL_NONADDRESSABLE_P (field))
-           {
-             to_rtx = copy_rtx (to_rtx);
-             MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
-           }
-
-         store_constructor_field (to_rtx, bitsize, bitpos, mode,
-                                  value, type, cleared,
-                                  get_alias_set (TREE_TYPE (field)));
-       }
-    }
-  else if (TREE_CODE (type) == ARRAY_TYPE
-          || TREE_CODE (type) == VECTOR_TYPE)
-    {
-      tree elt;
-      int i;
-      int need_to_clear;
-      tree domain = TYPE_DOMAIN (type);
-      tree elttype = TREE_TYPE (type);
-      int const_bounds_p;
-      HOST_WIDE_INT minelt = 0;
-      HOST_WIDE_INT maxelt = 0;
-
-      /* Vectors are like arrays, but the domain is stored via an array
-        type indirectly.  */
-      if (TREE_CODE (type) == VECTOR_TYPE)
-       {
-         /* 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)));
-       }
-
-      const_bounds_p = (TYPE_MIN_VALUE (domain)
-                       && TYPE_MAX_VALUE (domain)
-                       && host_integerp (TYPE_MIN_VALUE (domain), 0)
-                       && host_integerp (TYPE_MAX_VALUE (domain), 0));
+           if (MEM_P (to_rtx) && !MEM_KEEP_ALIAS_SET_P (to_rtx)
+               && DECL_NONADDRESSABLE_P (field))
+             {
+               to_rtx = copy_rtx (to_rtx);
+               MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
+             }
+           
+           store_constructor_field (to_rtx, bitsize, bitpos, mode,
+                                    value, type, cleared,
+                                    get_alias_set (TREE_TYPE (field)));
+         }
+       break;
+      }
+    case ARRAY_TYPE:
+      {
+       tree elt;
+       int i;
+       int need_to_clear;
+       tree domain;
+       tree elttype = TREE_TYPE (type);
+       int const_bounds_p;
+       HOST_WIDE_INT minelt = 0;
+       HOST_WIDE_INT maxelt = 0;
+
+       domain = TYPE_DOMAIN (type);
+       const_bounds_p = (TYPE_MIN_VALUE (domain)
+                         && TYPE_MAX_VALUE (domain)
+                         && host_integerp (TYPE_MIN_VALUE (domain), 0)
+                         && host_integerp (TYPE_MAX_VALUE (domain), 0));
+
+       /* If we have constant bounds for the range of the type, get them.  */
+       if (const_bounds_p)
+         {
+           minelt = tree_low_cst (TYPE_MIN_VALUE (domain), 0);
+           maxelt = tree_low_cst (TYPE_MAX_VALUE (domain), 0);
+         }
 
-      /* If we have constant bounds for the range of the type, get them.  */
-      if (const_bounds_p)
-       {
-         minelt = tree_low_cst (TYPE_MIN_VALUE (domain), 0);
-         maxelt = tree_low_cst (TYPE_MAX_VALUE (domain), 0);
-       }
+       /* 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)
+         need_to_clear = 0;
+       else if (REG_P (target) && TREE_STATIC (exp))
+         need_to_clear = 1;
+       else
+         {
+           HOST_WIDE_INT count = 0, zero_count = 0;
+           need_to_clear = ! const_bounds_p;
+           
+           /* This loop is a more accurate version of the loop in
+              mostly_zeros_p (it handles RANGE_EXPR in an index).  It
+              is also needed to check for missing elements.  */
+           for (elt = CONSTRUCTOR_ELTS (exp);
+                elt != NULL_TREE && ! need_to_clear;
+                elt = TREE_CHAIN (elt))
+             {
+               tree index = TREE_PURPOSE (elt);
+               HOST_WIDE_INT this_node_count;
+               
+               if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
+                 {
+                   tree lo_index = TREE_OPERAND (index, 0);
+                   tree hi_index = TREE_OPERAND (index, 1);
+                   
+                   if (! host_integerp (lo_index, 1)
+                       || ! host_integerp (hi_index, 1))
+                     {
+                       need_to_clear = 1;
+                       break;
+                     }
+                   
+                   this_node_count = (tree_low_cst (hi_index, 1)
+                                      - tree_low_cst (lo_index, 1) + 1);
+                 }
+               else
+                 this_node_count = 1;
+               
+               count += this_node_count;
+               if (mostly_zeros_p (TREE_VALUE (elt)))
+                 zero_count += this_node_count;
+             }
+           
+           /* Clear the entire array first if there are any missing
+              elements, or if the incidence of zero elements is >=
+              75%.  */
+           if (! need_to_clear
+               && (count < maxelt - minelt + 1
+                   || 4 * zero_count >= 3 * count))
+             need_to_clear = 1;
+         }
+       
+       if (need_to_clear && size > 0)
+         {
+           if (REG_P (target))
+             emit_move_insn (target,  CONST0_RTX (GET_MODE (target)));
+           else
+             clear_storage (target, GEN_INT (size));
+           cleared = 1;
+         }
 
-      /* 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)))
-       need_to_clear = 1;
-      else
-       {
-         HOST_WIDE_INT count = 0, zero_count = 0;
-         need_to_clear = ! const_bounds_p;
-
-         /* This loop is a more accurate version of the loop in
-            mostly_zeros_p (it handles RANGE_EXPR in an index).
-            It is also needed to check for missing elements.  */
-         for (elt = CONSTRUCTOR_ELTS (exp);
-              elt != NULL_TREE && ! need_to_clear;
-              elt = TREE_CHAIN (elt))
-           {
-             tree index = TREE_PURPOSE (elt);
-             HOST_WIDE_INT this_node_count;
+       if (!cleared && REG_P (target))
+         /* Inform later passes that the old value is dead.  */
+         emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
 
-             if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
-               {
-                 tree lo_index = TREE_OPERAND (index, 0);
-                 tree hi_index = TREE_OPERAND (index, 1);
+       /* Store each element of the constructor into the
+          corresponding element of TARGET, determined by counting the
+          elements.  */
+       for (elt = CONSTRUCTOR_ELTS (exp), i = 0;
+            elt;
+            elt = TREE_CHAIN (elt), i++)
+         {
+           enum machine_mode mode;
+           HOST_WIDE_INT bitsize;
+           HOST_WIDE_INT bitpos;
+           int unsignedp;
+           tree value = TREE_VALUE (elt);
+           tree index = TREE_PURPOSE (elt);
+           rtx xtarget = target;
+           
+           if (cleared && initializer_zerop (value))
+             continue;
+           
+           unsignedp = TYPE_UNSIGNED (elttype);
+           mode = TYPE_MODE (elttype);
+           if (mode == BLKmode)
+             bitsize = (host_integerp (TYPE_SIZE (elttype), 1)
+                        ? tree_low_cst (TYPE_SIZE (elttype), 1)
+                        : -1);
+           else
+             bitsize = GET_MODE_BITSIZE (mode);
+           
+           if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
+             {
+               tree lo_index = TREE_OPERAND (index, 0);
+               tree hi_index = TREE_OPERAND (index, 1);
+               rtx index_r, pos_rtx;
+               HOST_WIDE_INT lo, hi, count;
+               tree position;
+               
+               /* If the range is constant and "small", unroll the loop.  */
+               if (const_bounds_p
+                   && host_integerp (lo_index, 0)
+                   && host_integerp (hi_index, 0)
+                   && (lo = tree_low_cst (lo_index, 0),
+                       hi = tree_low_cst (hi_index, 0),
+                       count = hi - lo + 1,
+                       (!MEM_P (target)
+                        || count <= 2
+                        || (host_integerp (TYPE_SIZE (elttype), 1)
+                            && (tree_low_cst (TYPE_SIZE (elttype), 1) * count
+                                <= 40 * 8)))))
+                 {
+                   lo -= minelt;  hi -= minelt;
+                   for (; lo <= hi; lo++)
+                     {
+                       bitpos = lo * tree_low_cst (TYPE_SIZE (elttype), 0);
+                       
+                       if (MEM_P (target)
+                           && !MEM_KEEP_ALIAS_SET_P (target)
+                           && TREE_CODE (type) == ARRAY_TYPE
+                           && TYPE_NONALIASED_COMPONENT (type))
+                         {
+                           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));
+                     }
+                 }
+               else
+                 {
+                   rtx loop_start = gen_label_rtx ();
+                   rtx loop_end = gen_label_rtx ();
+                   tree exit_cond;
+                   
+                   expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
+                   unsignedp = TYPE_UNSIGNED (domain);
+                   
+                   index = build_decl (VAR_DECL, NULL_TREE, domain);
+                   
+                   index_r
+                     = gen_reg_rtx (promote_mode (domain, DECL_MODE (index),
+                                                  &unsignedp, 0));
+                   SET_DECL_RTL (index, index_r);
+                   store_expr (lo_index, index_r, 0);
+                   
+                   /* Build the head of the loop.  */
+                   do_pending_stack_adjust ();
+                   emit_label (loop_start);
+
+                   /* Assign value to element index.  */
+                   position
+                     = convert (ssizetype,
+                                fold (build2 (MINUS_EXPR, TREE_TYPE (index),
+                                              index, TYPE_MIN_VALUE (domain))));
+                   position = size_binop (MULT_EXPR, position,
+                                          convert (ssizetype,
+                                                   TYPE_SIZE_UNIT (elttype)));
+                   
+                   pos_rtx = expand_expr (position, 0, VOIDmode, 0);
+                   xtarget = offset_address (target, pos_rtx,
+                                             highest_pow2_factor (position));
+                   xtarget = adjust_address (xtarget, mode, 0);
+                   if (TREE_CODE (value) == CONSTRUCTOR)
+                     store_constructor (value, xtarget, cleared,
+                                        bitsize / BITS_PER_UNIT);
+                   else
+                     store_expr (value, xtarget, 0);
+
+                   /* Generate a conditional jump to exit the loop.  */
+                   exit_cond = build2 (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_assignment (index,
+                                      build2 (PLUS_EXPR, TREE_TYPE (index),
+                                              index, integer_one_node), 0);
+                   
+                   emit_jump (loop_start);
+                   
+                   /* Build the end of the loop.  */
+                   emit_label (loop_end);
+                 }
+             }
+           else if ((index != 0 && ! host_integerp (index, 0))
+                    || ! host_integerp (TYPE_SIZE (elttype), 1))
+             {
+               tree position;
+               
+               if (index == 0)
+                 index = ssize_int (1);
+               
+               if (minelt)
+                 index = fold_convert (ssizetype,
+                                       fold (build2 (MINUS_EXPR,
+                                                     TREE_TYPE (index),
+                                                     index,
+                                                     TYPE_MIN_VALUE (domain))));
+               
+               position = size_binop (MULT_EXPR, index,
+                                      convert (ssizetype,
+                                               TYPE_SIZE_UNIT (elttype)));
+               xtarget = offset_address (target,
+                                         expand_expr (position, 0, VOIDmode, 0),
+                                         highest_pow2_factor (position));
+               xtarget = adjust_address (xtarget, mode, 0);
+               store_expr (value, xtarget, 0);
+             }
+           else
+             {
+               if (index != 0)
+                 bitpos = ((tree_low_cst (index, 0) - minelt)
+                           * tree_low_cst (TYPE_SIZE (elttype), 1));
+               else
+                 bitpos = (i * tree_low_cst (TYPE_SIZE (elttype), 1));
+               
+               if (MEM_P (target) && !MEM_KEEP_ALIAS_SET_P (target)
+                   && TREE_CODE (type) == ARRAY_TYPE
+                   && TYPE_NONALIASED_COMPONENT (type))
+                 {
+                   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));
+             }
+         }
+       break;
+      }
 
-                 if (! host_integerp (lo_index, 1)
-                     || ! host_integerp (hi_index, 1))
-                   {
-                     need_to_clear = 1;
-                     break;
-                   }
-
-                 this_node_count = (tree_low_cst (hi_index, 1)
-                                    - tree_low_cst (lo_index, 1) + 1);
-               }
-             else
-               this_node_count = 1;
-
-             count += this_node_count;
-             if (mostly_zeros_p (TREE_VALUE (elt)))
-               zero_count += this_node_count;
-           }
-
-         /* Clear the entire array first if there are any missing elements,
-            or if the incidence of zero elements is >= 75%.  */
-         if (! need_to_clear
-             && (count < maxelt - minelt + 1 || 4 * zero_count >= 3 * count))
-           need_to_clear = 1;
-       }
-
-      if (need_to_clear && size > 0)
-       {
-         if (! cleared)
-           {
-             if (REG_P (target))
-               emit_move_insn (target,  CONST0_RTX (GET_MODE (target)));
-             else
-               clear_storage (target, GEN_INT (size));
-           }
-         cleared = 1;
-       }
-      else if (REG_P (target))
-       /* Inform later passes that the old value is dead.  */
-       emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
-
-      /* Store each element of the constructor into
-        the corresponding element of TARGET, determined
-        by counting the elements.  */
-      for (elt = CONSTRUCTOR_ELTS (exp), i = 0;
-          elt;
-          elt = TREE_CHAIN (elt), i++)
-       {
-         enum machine_mode mode;
-         HOST_WIDE_INT bitsize;
-         HOST_WIDE_INT bitpos;
-         int unsignedp;
-         tree value = TREE_VALUE (elt);
-         tree index = TREE_PURPOSE (elt);
-         rtx xtarget = target;
-
-         if (cleared && is_zeros_p (value))
-           continue;
-
-         unsignedp = TREE_UNSIGNED (elttype);
-         mode = TYPE_MODE (elttype);
-         if (mode == BLKmode)
-           bitsize = (host_integerp (TYPE_SIZE (elttype), 1)
-                      ? tree_low_cst (TYPE_SIZE (elttype), 1)
-                      : -1);
-         else
-           bitsize = GET_MODE_BITSIZE (mode);
-
-         if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
-           {
-             tree lo_index = TREE_OPERAND (index, 0);
-             tree hi_index = TREE_OPERAND (index, 1);
-             rtx index_r, pos_rtx, loop_end;
-             struct nesting *loop;
-             HOST_WIDE_INT lo, hi, count;
-             tree position;
-
-             /* If the range is constant and "small", unroll the loop.  */
-             if (const_bounds_p
-                 && host_integerp (lo_index, 0)
-                 && host_integerp (hi_index, 0)
-                 && (lo = tree_low_cst (lo_index, 0),
-                     hi = tree_low_cst (hi_index, 0),
-                     count = hi - lo + 1,
-                     (GET_CODE (target) != MEM
-                      || count <= 2
-                      || (host_integerp (TYPE_SIZE (elttype), 1)
-                          && (tree_low_cst (TYPE_SIZE (elttype), 1) * count
-                              <= 40 * 8)))))
-               {
-                 lo -= minelt;  hi -= minelt;
-                 for (; lo <= hi; lo++)
-                   {
-                     bitpos = lo * tree_low_cst (TYPE_SIZE (elttype), 0);
-
-                     if (GET_CODE (target) == MEM
-                         && !MEM_KEEP_ALIAS_SET_P (target)
-                         && TREE_CODE (type) == ARRAY_TYPE
-                         && TYPE_NONALIASED_COMPONENT (type))
-                       {
-                         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));
-                   }
-               }
-             else
-               {
-                 expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
-                 loop_end = gen_label_rtx ();
-
-                 unsignedp = TREE_UNSIGNED (domain);
-
-                 index = build_decl (VAR_DECL, NULL_TREE, domain);
-
-                 index_r
-                   = gen_reg_rtx (promote_mode (domain, DECL_MODE (index),
-                                                &unsignedp, 0));
-                 SET_DECL_RTL (index, index_r);
-                 if (TREE_CODE (value) == SAVE_EXPR
-                     && SAVE_EXPR_RTL (value) == 0)
-                   {
-                     /* Make sure value gets expanded once before the
-                         loop.  */
-                     expand_expr (value, const0_rtx, VOIDmode, 0);
-                     emit_queue ();
-                   }
-                 store_expr (lo_index, index_r, 0);
-                 loop = expand_start_loop (0);
-
-                 /* Assign value to element index.  */
-                 position
-                   = convert (ssizetype,
-                              fold (build (MINUS_EXPR, TREE_TYPE (index),
-                                           index, TYPE_MIN_VALUE (domain))));
-                 position = size_binop (MULT_EXPR, position,
-                                        convert (ssizetype,
-                                                 TYPE_SIZE_UNIT (elttype)));
-
-                 pos_rtx = expand_expr (position, 0, VOIDmode, 0);
-                 xtarget = offset_address (target, pos_rtx,
-                                           highest_pow2_factor (position));
-                 xtarget = adjust_address (xtarget, mode, 0);
-                 if (TREE_CODE (value) == CONSTRUCTOR)
-                   store_constructor (value, xtarget, cleared,
-                                      bitsize / BITS_PER_UNIT);
-                 else
-                   store_expr (value, xtarget, 0);
-
-                 expand_exit_loop_if_false (loop,
-                                            build (LT_EXPR, integer_type_node,
-                                                   index, hi_index));
-
-                 expand_increment (build (PREINCREMENT_EXPR,
-                                          TREE_TYPE (index),
-                                          index, integer_one_node), 0, 0);
-                 expand_end_loop ();
-                 emit_label (loop_end);
-               }
-           }
-         else if ((index != 0 && ! host_integerp (index, 0))
-                  || ! host_integerp (TYPE_SIZE (elttype), 1))
-           {
-             tree position;
-
-             if (index == 0)
-               index = ssize_int (1);
-
-             if (minelt)
-               index = convert (ssizetype,
-                                fold (build (MINUS_EXPR, index,
-                                             TYPE_MIN_VALUE (domain))));
-
-             position = size_binop (MULT_EXPR, index,
-                                    convert (ssizetype,
-                                             TYPE_SIZE_UNIT (elttype)));
-             xtarget = offset_address (target,
-                                       expand_expr (position, 0, VOIDmode, 0),
-                                       highest_pow2_factor (position));
-             xtarget = adjust_address (xtarget, mode, 0);
-             store_expr (value, xtarget, 0);
-           }
-         else
-           {
-             if (index != 0)
-               bitpos = ((tree_low_cst (index, 0) - minelt)
-                         * tree_low_cst (TYPE_SIZE (elttype), 1));
-             else
-               bitpos = (i * tree_low_cst (TYPE_SIZE (elttype), 1));
-
-             if (GET_CODE (target) == MEM && !MEM_KEEP_ALIAS_SET_P (target)
-                 && TREE_CODE (type) == ARRAY_TYPE
-                 && TYPE_NONALIASED_COMPONENT (type))
-               {
-                 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));
-
-           }
-       }
-    }
-
-  /* Set constructor assignments.  */
-  else if (TREE_CODE (type) == SET_TYPE)
-    {
-      tree elt = CONSTRUCTOR_ELTS (exp);
-      unsigned HOST_WIDE_INT nbytes = int_size_in_bytes (type), nbits;
-      tree domain = TYPE_DOMAIN (type);
-      tree domain_min, domain_max, bitlength;
-
-      /* The default implementation strategy is to extract the constant
-        parts of the constructor, use that to initialize the target,
-        and then "or" in whatever non-constant ranges we need in addition.
-
-        If a large set is all zero or all ones, it is
-        probably better to set it using memset (if available) or bzero.
-        Also, if a large set has just a single range, it may also be
-        better to first clear all the first clear the set (using
-        bzero/memset), and set the bits we want.  */
-
-      /* Check for all zeros.  */
-      if (elt == NULL_TREE && size > 0)
-       {
-         if (!cleared)
-           clear_storage (target, GEN_INT (size));
-         return;
-       }
-
-      domain_min = convert (sizetype, TYPE_MIN_VALUE (domain));
-      domain_max = convert (sizetype, TYPE_MAX_VALUE (domain));
-      bitlength = size_binop (PLUS_EXPR,
-                             size_diffop (domain_max, domain_min),
-                             ssize_int (1));
-
-      nbits = tree_low_cst (bitlength, 1);
-
-      /* For "small" sets, or "medium-sized" (up to 32 bytes) sets that
-        are "complicated" (more than one range), initialize (the
-        constant parts) by copying from a constant.  */
-      if (GET_MODE (target) != BLKmode || nbits <= 2 * BITS_PER_WORD
-         || (nbytes <= 32 && TREE_CHAIN (elt) != NULL_TREE))
-       {
-         unsigned int set_word_size = TYPE_ALIGN (TREE_TYPE (exp));
-         enum machine_mode mode = mode_for_size (set_word_size, MODE_INT, 1);
-         char *bit_buffer = alloca (nbits);
-         HOST_WIDE_INT word = 0;
-         unsigned int bit_pos = 0;
-         unsigned int ibit = 0;
-         unsigned int offset = 0;  /* In bytes from beginning of set.  */
-
-         elt = get_set_constructor_bits (exp, bit_buffer, nbits);
-         for (;;)
-           {
-             if (bit_buffer[ibit])
-               {
-                 if (BYTES_BIG_ENDIAN)
-                   word |= (1 << (set_word_size - 1 - bit_pos));
-                 else
-                   word |= 1 << bit_pos;
-               }
-
-             bit_pos++;  ibit++;
-             if (bit_pos >= set_word_size || ibit == nbits)
-               {
-                 if (word != 0 || ! cleared)
-                   {
-                     rtx datum = GEN_INT (word);
-                     rtx to_rtx;
-
-                     /* The assumption here is that it is safe to use
-                        XEXP if the set is multi-word, but not if
-                        it's single-word.  */
-                     if (GET_CODE (target) == MEM)
-                       to_rtx = adjust_address (target, mode, offset);
-                     else if (offset == 0)
-                       to_rtx = target;
-                     else
-                       abort ();
-                     emit_move_insn (to_rtx, datum);
-                   }
+    case VECTOR_TYPE:
+      {
+       tree elt;
+       int i;
+       int need_to_clear;
+       int icode = 0;
+       tree elttype = TREE_TYPE (type);
+       int elt_size = tree_low_cst (TYPE_SIZE (elttype), 1);
+       enum machine_mode eltmode = TYPE_MODE (elttype);
+       HOST_WIDE_INT bitsize;
+       HOST_WIDE_INT bitpos;
+       rtx *vector = NULL;
+       unsigned n_elts;
+       
+       gcc_assert (eltmode != BLKmode);
+       
+       n_elts = TYPE_VECTOR_SUBPARTS (type);
+       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;
+               
+               vector = alloca (n_elts);
+               for (i = 0; i < n_elts; i++)
+                 vector [i] = CONST0_RTX (GET_MODE_INNER (mode));
+             }
+         }
+       
+       /* If the constructor has fewer elements than the vector,
+          clear the whole array first.  Similarly if this is static
+          constructor of a non-BLKmode object.  */
+       if (cleared)
+         need_to_clear = 0;
+       else if (REG_P (target) && TREE_STATIC (exp))
+         need_to_clear = 1;
+       else
+         {
+           unsigned HOST_WIDE_INT count = 0, zero_count = 0;
+           
+           for (elt = CONSTRUCTOR_ELTS (exp);
+                elt != NULL_TREE;
+                elt = TREE_CHAIN (elt))
+             {
+               int n_elts_here = tree_low_cst
+                 (int_const_binop (TRUNC_DIV_EXPR,
+                                   TYPE_SIZE (TREE_TYPE (TREE_VALUE (elt))),
+                                   TYPE_SIZE (elttype), 0), 1);
+               
+               count += n_elts_here;
+               if (mostly_zeros_p (TREE_VALUE (elt)))
+                 zero_count += n_elts_here;
+             }
 
-                 if (ibit == nbits)
-                   break;
-                 word = 0;
-                 bit_pos = 0;
-                 offset += set_word_size / BITS_PER_UNIT;
-               }
-           }
-       }
-      else if (!cleared)
-       /* Don't bother clearing storage if the set is all ones.  */
-       if (TREE_CHAIN (elt) != NULL_TREE
-           || (TREE_PURPOSE (elt) == NULL_TREE
-               ? nbits != 1
-               : ( ! host_integerp (TREE_VALUE (elt), 0)
-                  || ! host_integerp (TREE_PURPOSE (elt), 0)
-                  || (tree_low_cst (TREE_VALUE (elt), 0)
-                      - tree_low_cst (TREE_PURPOSE (elt), 0) + 1
-                      != (HOST_WIDE_INT) nbits))))
-         clear_storage (target, expr_size (exp));
-
-      for (; elt != NULL_TREE; elt = TREE_CHAIN (elt))
-       {
-         /* Start of range of element or NULL.  */
-         tree startbit = TREE_PURPOSE (elt);
-         /* End of range of element, or element value.  */
-         tree endbit   = TREE_VALUE (elt);
-         HOST_WIDE_INT startb, endb;
-         rtx bitlength_rtx, startbit_rtx, endbit_rtx, targetx;
-
-         bitlength_rtx = expand_expr (bitlength,
-                                      NULL_RTX, MEM, EXPAND_CONST_ADDRESS);
-
-         /* Handle non-range tuple element like [ expr ].  */
-         if (startbit == NULL_TREE)
-           {
-             startbit = save_expr (endbit);
-             endbit = startbit;
-           }
+           /* Clear the entire vector first if there are any missing elements,
+              or if the incidence of zero elements is >= 75%.  */
+           need_to_clear = (count < n_elts || 4 * zero_count >= 3 * count);
+         }
+       
+       if (need_to_clear && size > 0 && !vector)
+         {
+           if (REG_P (target))
+             emit_move_insn (target,  CONST0_RTX (GET_MODE (target)));
+           else
+             clear_storage (target, GEN_INT (size));
+           cleared = 1;
+         }
+       
+       if (!cleared && REG_P (target))
+         /* Inform later passes that the old value is dead.  */
+         emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
+
+        /* Store each element of the constructor into the corresponding
+          element of TARGET, determined by counting the elements.  */
+       for (elt = CONSTRUCTOR_ELTS (exp), i = 0;
+            elt;
+            elt = TREE_CHAIN (elt), i += bitsize / elt_size)
+         {
+           tree value = TREE_VALUE (elt);
+           tree index = TREE_PURPOSE (elt);
+           HOST_WIDE_INT eltpos;
+           
+           bitsize = tree_low_cst (TYPE_SIZE (TREE_TYPE (value)), 1);
+           if (cleared && initializer_zerop (value))
+             continue;
+           
+           if (index != 0)
+             eltpos = tree_low_cst (index, 1);
+           else
+             eltpos = i;
+           
+           if (vector)
+             {
+               /* Vector CONSTRUCTORs should only be built from smaller
+                  vectors in the case of BLKmode vectors.  */
+               gcc_assert (TREE_CODE (TREE_TYPE (value)) != VECTOR_TYPE);
+               vector[eltpos] = expand_expr (value, NULL_RTX, VOIDmode, 0);
+             }
+           else
+             {
+               enum machine_mode value_mode =
+                 TREE_CODE (TREE_TYPE (value)) == VECTOR_TYPE
+                 ? TYPE_MODE (TREE_TYPE (value))
+                 : eltmode;
+               bitpos = eltpos * elt_size;
+               store_constructor_field (target, bitsize, bitpos,
+                                        value_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))));
+       break;
+      }
 
-         startbit = convert (sizetype, startbit);
-         endbit = convert (sizetype, endbit);
-         if (! integer_zerop (domain_min))
-           {
-             startbit = size_binop (MINUS_EXPR, startbit, domain_min);
-             endbit = size_binop (MINUS_EXPR, endbit, domain_min);
-           }
-         startbit_rtx = expand_expr (startbit, NULL_RTX, MEM,
+      /* Set constructor assignments.  */
+    case SET_TYPE:
+      {
+       tree elt = CONSTRUCTOR_ELTS (exp);
+       unsigned HOST_WIDE_INT nbytes = int_size_in_bytes (type), nbits;
+       tree domain = TYPE_DOMAIN (type);
+       tree domain_min, domain_max, bitlength;
+       
+       /* The default implementation strategy is to extract the
+          constant parts of the constructor, use that to initialize
+          the target, and then "or" in whatever non-constant ranges
+          we need in addition.
+
+          If a large set is all zero or all ones, it is probably
+          better to set it using memset.  Also, if a large set has
+          just a single range, it may also be better to first clear
+          all the first clear the set (using memset), and set the
+          bits we want.  */
+
+       /* Check for all zeros.  */
+       if (elt == NULL_TREE && size > 0)
+         {
+           if (!cleared)
+             clear_storage (target, GEN_INT (size));
+           return;
+         }
+       
+       domain_min = convert (sizetype, TYPE_MIN_VALUE (domain));
+       domain_max = convert (sizetype, TYPE_MAX_VALUE (domain));
+       bitlength = size_binop (PLUS_EXPR,
+                               size_diffop (domain_max, domain_min),
+                               ssize_int (1));
+       
+       nbits = tree_low_cst (bitlength, 1);
+
+        /* For "small" sets, or "medium-sized" (up to 32 bytes) sets
+          that are "complicated" (more than one range), initialize
+          (the constant parts) by copying from a constant.  */
+       if (GET_MODE (target) != BLKmode || nbits <= 2 * BITS_PER_WORD
+           || (nbytes <= 32 && TREE_CHAIN (elt) != NULL_TREE))
+         {
+           unsigned int set_word_size = TYPE_ALIGN (TREE_TYPE (exp));
+           enum machine_mode mode = mode_for_size (set_word_size, MODE_INT, 1);
+           char *bit_buffer = alloca (nbits);
+           HOST_WIDE_INT word = 0;
+           unsigned int bit_pos = 0;
+           unsigned int ibit = 0;
+           unsigned int offset = 0;  /* In bytes from beginning of set.  */
+           
+           elt = get_set_constructor_bits (exp, bit_buffer, nbits);
+           for (;;)
+             {
+               if (bit_buffer[ibit])
+                 {
+                   if (BYTES_BIG_ENDIAN)
+                     word |= (1 << (set_word_size - 1 - bit_pos));
+                   else
+                     word |= 1 << bit_pos;
+                 }
+               
+               bit_pos++;  ibit++;
+               if (bit_pos >= set_word_size || ibit == nbits)
+                 {
+                   if (word != 0 || ! cleared)
+                     {
+                       rtx datum = gen_int_mode (word, mode);
+                       rtx to_rtx;
+                       
+                       /* The assumption here is that it is safe to
+                          use XEXP if the set is multi-word, but not
+                          if it's single-word.  */
+                       if (MEM_P (target))
+                         to_rtx = adjust_address (target, mode, offset);
+                       else
+                         {
+                           gcc_assert (!offset);
+                           to_rtx = target;
+                         }
+                       emit_move_insn (to_rtx, datum);
+                     }
+                   
+                   if (ibit == nbits)
+                     break;
+                   word = 0;
+                   bit_pos = 0;
+                   offset += set_word_size / BITS_PER_UNIT;
+                 }
+             }
+         }
+       else if (!cleared)
+         /* Don't bother clearing storage if the set is all ones.  */
+         if (TREE_CHAIN (elt) != NULL_TREE
+             || (TREE_PURPOSE (elt) == NULL_TREE
+                 ? nbits != 1
+                 : ( ! host_integerp (TREE_VALUE (elt), 0)
+                     || ! host_integerp (TREE_PURPOSE (elt), 0)
+                     || (tree_low_cst (TREE_VALUE (elt), 0)
+                         - tree_low_cst (TREE_PURPOSE (elt), 0) + 1
+                         != (HOST_WIDE_INT) nbits))))
+           clear_storage (target, expr_size (exp));
+       
+       for (; elt != NULL_TREE; elt = TREE_CHAIN (elt))
+         {
+           /* Start of range of element or NULL.  */
+           tree startbit = TREE_PURPOSE (elt);
+           /* End of range of element, or element value.  */
+           tree endbit   = TREE_VALUE (elt);
+           HOST_WIDE_INT startb, endb;
+           rtx bitlength_rtx, startbit_rtx, endbit_rtx, targetx;
+           
+           bitlength_rtx = expand_expr (bitlength,
+                                        NULL_RTX, MEM, EXPAND_CONST_ADDRESS);
+           
+           /* Handle non-range tuple element like [ expr ].  */
+           if (startbit == NULL_TREE)
+             {
+               startbit = save_expr (endbit);
+               endbit = startbit;
+             }
+           
+           startbit = convert (sizetype, startbit);
+           endbit = convert (sizetype, endbit);
+           if (! integer_zerop (domain_min))
+             {
+               startbit = size_binop (MINUS_EXPR, startbit, domain_min);
+               endbit = size_binop (MINUS_EXPR, endbit, domain_min);
+             }
+           startbit_rtx = expand_expr (startbit, NULL_RTX, MEM,
+                                       EXPAND_CONST_ADDRESS);
+           endbit_rtx = expand_expr (endbit, NULL_RTX, MEM,
                                      EXPAND_CONST_ADDRESS);
-         endbit_rtx = expand_expr (endbit, NULL_RTX, MEM,
-                                   EXPAND_CONST_ADDRESS);
-
-         if (REG_P (target))
-           {
-             targetx
-               = assign_temp
-                 ((build_qualified_type ((*lang_hooks.types.type_for_mode)
+           
+           if (REG_P (target))
+             {
+               targetx
+                 = assign_temp
+                 ((build_qualified_type (lang_hooks.types.type_for_mode
                                          (GET_MODE (target), 0),
                                          TYPE_QUAL_CONST)),
                   0, 1, 1);
-             emit_move_insn (targetx, target);
-           }
+               emit_move_insn (targetx, target);
+             }
+           
+           else
+             {
+               gcc_assert (MEM_P (target));
+               targetx = target;
+             }
 
-         else if (GET_CODE (target) == MEM)
-           targetx = target;
-         else
-           abort ();
-
-         /* Optimization:  If startbit and endbit are constants divisible
-            by BITS_PER_UNIT, call memset instead.  */
-         if (TARGET_MEM_FUNCTIONS
-             && TREE_CODE (startbit) == INTEGER_CST
-             && TREE_CODE (endbit) == INTEGER_CST
-             && (startb = TREE_INT_CST_LOW (startbit)) % BITS_PER_UNIT == 0
-             && (endb = TREE_INT_CST_LOW (endbit) + 1) % BITS_PER_UNIT == 0)
-           {
-             emit_library_call (memset_libfunc, LCT_NORMAL,
-                                VOIDmode, 3,
-                                plus_constant (XEXP (targetx, 0),
-                                               startb / BITS_PER_UNIT),
-                                Pmode,
-                                constm1_rtx, TYPE_MODE (integer_type_node),
-                                GEN_INT ((endb - startb) / BITS_PER_UNIT),
-                                TYPE_MODE (sizetype));
-           }
-         else
-           emit_library_call (setbits_libfunc, LCT_NORMAL,
-                              VOIDmode, 4, XEXP (targetx, 0),
-                              Pmode, bitlength_rtx, TYPE_MODE (sizetype),
-                              startbit_rtx, TYPE_MODE (sizetype),
-                              endbit_rtx, TYPE_MODE (sizetype));
-
-         if (REG_P (target))
-           emit_move_insn (target, targetx);
-       }
+           /* Optimization:  If startbit and endbit are constants divisible
+              by BITS_PER_UNIT, call memset instead.  */
+           if (TREE_CODE (startbit) == INTEGER_CST
+               && TREE_CODE (endbit) == INTEGER_CST
+               && (startb = TREE_INT_CST_LOW (startbit)) % BITS_PER_UNIT == 0
+               && (endb = TREE_INT_CST_LOW (endbit) + 1) % BITS_PER_UNIT == 0)
+             {
+               emit_library_call (memset_libfunc, LCT_NORMAL,
+                                  VOIDmode, 3,
+                                  plus_constant (XEXP (targetx, 0),
+                                                 startb / BITS_PER_UNIT),
+                                  Pmode,
+                                  constm1_rtx, TYPE_MODE (integer_type_node),
+                                  GEN_INT ((endb - startb) / BITS_PER_UNIT),
+                                  TYPE_MODE (sizetype));
+             }
+           else
+             emit_library_call (setbits_libfunc, LCT_NORMAL,
+                                VOIDmode, 4, XEXP (targetx, 0),
+                                Pmode, bitlength_rtx, TYPE_MODE (sizetype),
+                                startbit_rtx, TYPE_MODE (sizetype),
+                                endbit_rtx, TYPE_MODE (sizetype));
+           
+           if (REG_P (target))
+             emit_move_insn (target, targetx);
+         }
+       break;
+      }
+    default:
+      gcc_unreachable ();
     }
-
-  else
-    abort ();
 }
 
 /* Store the value of EXP (an expression tree)
@@ -5581,7 +5138,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);
@@ -5602,9 +5159,8 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
     {
       /* We're storing into a struct containing a single __complex.  */
 
-      if (bitpos != 0)
-       abort ();
-      return store_expr (exp, target, 0);
+      gcc_assert (!bitpos);
+      return store_expr (exp, target, value_mode != VOIDmode);
     }
 
   /* If the structure is in a register or if the component
@@ -5615,7 +5171,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.  */
@@ -5656,9 +5212,8 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
         boundary.  If so, we simply do a block copy.  */
       if (GET_MODE (target) == BLKmode && GET_MODE (temp) == BLKmode)
        {
-         if (GET_CODE (target) != MEM || GET_CODE (temp) != MEM
-             || bitpos % BITS_PER_UNIT != 0)
-           abort ();
+         gcc_assert (MEM_P (target) && MEM_P (temp)
+                     && !(bitpos % BITS_PER_UNIT));
 
          target = adjust_address (target, VOIDmode, bitpos / BITS_PER_UNIT);
          emit_block_move (target, temp,
@@ -5670,15 +5225,14 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
        }
 
       /* Store the value in the bitfield.  */
-      store_bit_field (target, bitsize, bitpos, mode, temp,
-                      int_size_in_bytes (type));
+      store_bit_field (target, bitsize, bitpos, mode, temp);
 
       if (value_mode != VOIDmode)
        {
          /* The caller wants an rtx for the value.
             If possible, avoid refetching from the bitfield itself.  */
          if (width_mask != 0
-             && ! (GET_CODE (target) == MEM && MEM_VOLATILE_P (target)))
+             && ! (MEM_P (target) && MEM_VOLATILE_P (target)))
            {
              tree count;
              enum machine_mode tmode;
@@ -5692,14 +5246,14 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
                                   gen_int_mode (width_mask, tmode),
                                   NULL_RTX);
 
-             count = build_int_2 (GET_MODE_BITSIZE (tmode) - bitsize, 0);
+             count = build_int_cst (NULL_TREE,
+                                    GET_MODE_BITSIZE (tmode) - bitsize);
              temp = expand_shift (LSHIFT_EXPR, tmode, temp, count, 0, 0);
              return expand_shift (RSHIFT_EXPR, tmode, temp, count, 0, 0);
            }
 
          return extract_bit_field (target, bitsize, bitpos, unsignedp,
-                                   NULL_RTX, value_mode, VOIDmode,
-                                   int_size_in_bytes (type));
+                                   NULL_RTX, value_mode, VOIDmode);
        }
       return const0_rtx;
     }
@@ -5711,7 +5265,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
@@ -5767,7 +5321,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
@@ -5778,17 +5331,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));
@@ -5813,15 +5366,13 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
       else if (TREE_CODE (exp) == COMPONENT_REF)
        {
          tree field = TREE_OPERAND (exp, 1);
-         tree this_offset = DECL_FIELD_OFFSET (field);
+         tree this_offset = component_ref_field_offset (exp);
 
          /* If this field hasn't been filled in yet, don't go
             past it.  This should only happen when folding expressions
             made during type construction.  */
          if (this_offset == 0)
            break;
-         else if (CONTAINS_PLACEHOLDER_P (this_offset))
-           this_offset = build (WITH_RECORD_EXPR, sizetype, this_offset, exp);
 
          offset = size_binop (PLUS_EXPR, offset, this_offset);
          bit_offset = size_binop (PLUS_EXPR, bit_offset,
@@ -5834,26 +5385,16 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
               || TREE_CODE (exp) == ARRAY_RANGE_REF)
        {
          tree index = TREE_OPERAND (exp, 1);
-         tree array = TREE_OPERAND (exp, 0);
-         tree domain = TYPE_DOMAIN (TREE_TYPE (array));
-         tree low_bound = (domain ? TYPE_MIN_VALUE (domain) : 0);
-         tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array)));
+         tree low_bound = array_ref_low_bound (exp);
+         tree unit_size = array_ref_element_size (exp);
 
          /* We assume all arrays have sizes that are a multiple of a byte.
             First subtract the lower bound, if any, in the type of the
             index, then convert to sizetype and multiply by the size of the
             array element.  */
-         if (low_bound != 0 && ! integer_zerop (low_bound))
-           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 (! integer_zerop (low_bound))
+           index = fold (build2 (MINUS_EXPR, TREE_TYPE (index),
+                                 index, low_bound));
 
          offset = size_binop (PLUS_EXPR, offset,
                               size_binop (MULT_EXPR,
@@ -5861,21 +5402,6 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
                                           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.  */
@@ -5917,6 +5443,99 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
   return exp;
 }
 
+/* Return a tree of sizetype representing the size, in bytes, of the element
+   of EXP, an ARRAY_REF.  */
+
+tree
+array_ref_element_size (tree exp)
+{
+  tree aligned_size = TREE_OPERAND (exp, 3);
+  tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+  /* If a size was specified in the ARRAY_REF, it's the size measured
+     in alignment units of the element type.  So multiply by that value.  */
+  if (aligned_size)
+    {
+      /* ??? tree_ssa_useless_type_conversion will eliminate casts to
+        sizetype from another type of the same width and signedness.  */
+      if (TREE_TYPE (aligned_size) != sizetype)
+       aligned_size = fold_convert (sizetype, aligned_size);
+      return size_binop (MULT_EXPR, aligned_size,
+                        size_int (TYPE_ALIGN_UNIT (elmt_type)));
+    }
+
+  /* Otherwise, take the size from that of the element type.  Substitute
+     any PLACEHOLDER_EXPR that we have.  */
+  else
+    return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_SIZE_UNIT (elmt_type), exp);
+}
+
+/* Return a tree representing the lower bound of the array mentioned in
+   EXP, an ARRAY_REF.  */
+
+tree
+array_ref_low_bound (tree exp)
+{
+  tree domain_type = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+  /* If a lower bound is specified in EXP, use it.  */
+  if (TREE_OPERAND (exp, 2))
+    return TREE_OPERAND (exp, 2);
+
+  /* Otherwise, if there is a domain type and it has a lower bound, use it,
+     substituting for a PLACEHOLDER_EXPR as needed.  */
+  if (domain_type && TYPE_MIN_VALUE (domain_type))
+    return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_MIN_VALUE (domain_type), exp);
+
+  /* Otherwise, return a zero of the appropriate type.  */
+  return build_int_cst (TREE_TYPE (TREE_OPERAND (exp, 1)), 0);
+}
+
+/* Return a tree representing the upper bound of the array mentioned in
+   EXP, an ARRAY_REF.  */
+
+tree
+array_ref_up_bound (tree exp)
+{
+  tree domain_type = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+  /* If there is a domain type and it has an upper bound, use it, substituting
+     for a PLACEHOLDER_EXPR as needed.  */
+  if (domain_type && TYPE_MAX_VALUE (domain_type))
+    return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_MAX_VALUE (domain_type), exp);
+
+  /* Otherwise fail.  */
+  return NULL_TREE;
+}
+
+/* Return a tree representing the offset, in bytes, of the field referenced
+   by EXP.  This does not include any offset in DECL_FIELD_BIT_OFFSET.  */
+
+tree
+component_ref_field_offset (tree exp)
+{
+  tree aligned_offset = TREE_OPERAND (exp, 2);
+  tree field = TREE_OPERAND (exp, 1);
+
+  /* If an offset was specified in the COMPONENT_REF, it's the offset measured
+     in units of DECL_OFFSET_ALIGN / BITS_PER_UNIT.  So multiply by that
+     value.  */
+  if (aligned_offset)
+    {
+      /* ??? tree_ssa_useless_type_conversion will eliminate casts to
+        sizetype from another type of the same width and signedness.  */
+      if (TREE_TYPE (aligned_offset) != sizetype)
+       aligned_offset = fold_convert (sizetype, aligned_offset);
+      return size_binop (MULT_EXPR, aligned_offset,
+                        size_int (DECL_OFFSET_ALIGN (field) / BITS_PER_UNIT));
+    }
+
+  /* Otherwise, take the offset from that of the field.  Substitute
+     any PLACEHOLDER_EXPR that we have.  */
+  else
+    return SUBSTITUTE_PLACEHOLDER_IN_EXPR (DECL_FIELD_OFFSET (field), exp);
+}
+
 /* Return 1 if T is an expression that get_inner_reference handles.  */
 
 int
@@ -5960,6 +5579,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))
+      && !MEM_P (SUBREG_REG (value)))
+    {
+      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
@@ -5982,10 +5615,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)
        {
@@ -6001,7 +5634,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)
        {
@@ -6051,7 +5684,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);
@@ -6060,7 +5693,7 @@ force_operand (rtx value, rtx target)
 #ifdef INSN_SCHEDULING
   /* On machines that have insn scheduling, we want all memory reference to be
      explicit, so we need to deal with such paradoxical SUBREGs.  */
-  if (GET_CODE (value) == SUBREG && GET_CODE (SUBREG_REG (value)) == MEM
+  if (GET_CODE (value) == SUBREG && MEM_P (SUBREG_REG (value))
       && (GET_MODE_SIZE (GET_MODE (value))
          > GET_MODE_SIZE (GET_MODE (SUBREG_REG (value)))))
     value
@@ -6088,7 +5721,6 @@ safe_from_p (rtx x, tree exp, int top_p)
 {
   rtx exp_rtl = 0;
   int i, nops;
-  static tree save_expr_list;
 
   if (x == 0
       /* If EXP has varying size, we MUST use a target since we currently
@@ -6105,7 +5737,7 @@ safe_from_p (rtx x, tree exp, int top_p)
              != INTEGER_CST)
          && GET_MODE (x) == BLKmode)
       /* If X is in the outgoing argument area, it is always safe.  */
-      || (GET_CODE (x) == MEM
+      || (MEM_P (x)
          && (XEXP (x, 0) == virtual_outgoing_args_rtx
              || (GET_CODE (XEXP (x, 0)) == PLUS
                  && XEXP (XEXP (x, 0), 0) == virtual_outgoing_args_rtx))))
@@ -6116,34 +5748,10 @@ 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
-     with optimization took about 28 minutes to compile -- even though it was
-     only a few lines long.  So we mark each SAVE_EXPR we see with TREE_PRIVATE
-     and turn that off when we are done.  We keep a list of the SAVE_EXPRs
-     we have processed.  Note that the only test of top_p was above.  */
-
-  if (top_p)
-    {
-      int rtn;
-      tree t;
-
-      save_expr_list = 0;
-
-      rtn = safe_from_p (x, exp, 0);
-
-      for (t = save_expr_list; t != 0; t = TREE_CHAIN (t))
-       TREE_PRIVATE (TREE_PURPOSE (t)) = 0;
-
-      return rtn;
-    }
-
   /* Now look at our tree code and possibly recurse.  */
   switch (TREE_CODE_CLASS (TREE_CODE (exp)))
     {
@@ -6173,11 +5781,19 @@ safe_from_p (rtx x, tree exp, int top_p)
       else
        return 0;
 
+    case 's':
+      /* The only case we look at here is the DECL_INITIAL inside a
+        DECL_EXPR.  */
+      return (TREE_CODE (exp) != DECL_EXPR
+             || TREE_CODE (DECL_EXPR_DECL (exp)) != VAR_DECL
+             || !DECL_INITIAL (DECL_EXPR_DECL (exp))
+             || safe_from_p (x, DECL_INITIAL (DECL_EXPR_DECL (exp)), 0));
+
     case '2':
     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);
@@ -6206,7 +5822,7 @@ safe_from_p (rtx x, tree exp, int top_p)
          if (DECL_P (exp))
            {
              if (!DECL_RTL_SET_P (exp)
-                 || GET_CODE (DECL_RTL (exp)) != MEM)
+                 || !MEM_P (DECL_RTL (exp)))
                return 0;
              else
                exp_rtl = XEXP (DECL_RTL (exp), 0);
@@ -6214,7 +5830,7 @@ safe_from_p (rtx x, tree exp, int top_p)
          break;
 
        case INDIRECT_REF:
-         if (GET_CODE (x) == MEM
+         if (MEM_P (x)
              && alias_sets_conflict_p (MEM_ALIAS_SET (x),
                                        get_alias_set (exp)))
            return 0;
@@ -6223,53 +5839,18 @@ 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)
-             || GET_CODE (x) == MEM)
+         if ((REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
+             || MEM_P (x))
            return 0;
          break;
 
-       case RTL_EXPR:
-         /* If a sequence exists, we would have to scan every instruction
-            in the sequence to see if it was safe.  This is probably not
-            worthwhile.  */
-         if (RTL_EXPR_SEQUENCE (exp))
-           return 0;
-
-         exp_rtl = RTL_EXPR_RTL (exp);
-         break;
-
        case WITH_CLEANUP_EXPR:
-         exp_rtl = WITH_CLEANUP_EXPR_RTL (exp);
-         break;
-
        case CLEANUP_POINT_EXPR:
-         return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
+         /* Lowered by gimplify.c.  */
+         gcc_unreachable ();
 
        case SAVE_EXPR:
-         exp_rtl = SAVE_EXPR_RTL (exp);
-         if (exp_rtl)
-           break;
-
-         /* If we've already scanned this, don't do it again.  Otherwise,
-            show we've scanned it and record for clearing the flag if we're
-            going on.  */
-         if (TREE_PRIVATE (exp))
-           return 1;
-
-         TREE_PRIVATE (exp) = 1;
-         if (! safe_from_p (x, TREE_OPERAND (exp, 0), 0))
-           {
-             TREE_PRIVATE (exp) = 0;
-             return 0;
-           }
-
-         save_expr_list = tree_cons (exp, NULL_TREE, save_expr_list);
-         return 1;
-
-       case BIND_EXPR:
-         /* The only operand we look at is operand 1.  The rest aren't
-            part of the expression.  */
-         return safe_from_p (x, TREE_OPERAND (exp, 1), 0);
+         return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
 
        default:
          break;
@@ -6289,7 +5870,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;
     }
 
@@ -6300,7 +5881,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;
        }
@@ -6308,7 +5889,7 @@ safe_from_p (rtx x, tree exp, int top_p)
       /* If the rtl is X, then it is not safe.  Otherwise, it is unless both
         are memory and they conflict.  */
       return ! (rtx_equal_p (x, exp_rtl)
-               || (GET_CODE (x) == MEM && GET_CODE (exp_rtl) == MEM
+               || (MEM_P (x) && MEM_P (exp_rtl)
                    && true_dependence (exp_rtl, VOIDmode, x,
                                        rtx_addr_varies_p)));
     }
@@ -6317,76 +5898,6 @@ safe_from_p (rtx x, tree exp, int top_p)
   return 1;
 }
 
-/* Subroutine of expand_expr: return rtx if EXP is a
-   variable or parameter; else return 0.  */
-
-static rtx
-var_rtx (tree exp)
-{
-  STRIP_NOPS (exp);
-  switch (TREE_CODE (exp))
-    {
-    case PARM_DECL:
-    case VAR_DECL:
-      return DECL_RTL (exp);
-    default:
-      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.  */
@@ -6439,7 +5950,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:
@@ -6457,83 +5968,219 @@ 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_UNIT (TREE_OPERAND (target, 1));
+  else
+    target_align = TYPE_ALIGN_UNIT (TREE_TYPE (target));
+  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;
-
-  for (placeholder_expr
-       = plist && *plist ? TREE_CHAIN (*plist) : placeholder_list;
-       placeholder_expr != 0;
-       placeholder_expr = TREE_CHAIN (placeholder_expr))
-    {
-      tree need_type = TYPE_MAIN_VARIANT (type);
-      tree elt;
-
-      /* Find the outermost reference that is of the type we want.  If none,
-        see if any object has a type that is a pointer to the type we
-        want.  */
-      for (elt = TREE_PURPOSE (placeholder_expr); elt != 0;
-          elt = ((TREE_CODE (elt) == COMPOUND_EXPR
-                  || TREE_CODE (elt) == COND_EXPR)
-                 ? TREE_OPERAND (elt, 1)
-                 : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
-                    || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
-                    || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
-                    || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
-                 ? TREE_OPERAND (elt, 0) : 0))
-       if (TYPE_MAIN_VARIANT (TREE_TYPE (elt)) == need_type)
-         {
-           if (plist)
-             *plist = placeholder_expr;
-           return elt;
-         }
+  if (DECL_EXTERNAL (var))
+    return;
 
-      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);
-         }
+  if (TREE_STATIC (var))
+    /* If this is an inlined copy of a static local variable,
+       look up the original decl.  */
+    var = DECL_ORIGIN (var);
+
+  if (TREE_STATIC (var)
+      ? !TREE_ASM_WRITTEN (var)
+      : !DECL_RTL_SET_P (var))
+    {
+      if (TREE_CODE (var) == VAR_DECL && DECL_VALUE_EXPR (var))
+       /* Should be ignored.  */;
+      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, 0, 0);
+      else
+       /* No expansion needed.  */
+       gcc_assert (TREE_CODE (var) == TYPE_DECL
+                   || TREE_CODE (var) == CONST_DECL
+                   || TREE_CODE (var) == FUNCTION_DECL
+                   || TREE_CODE (var) == LABEL_DECL);
     }
+}
 
-  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
+/* A subroutine of expand_expr.  Evaluate the address of EXP.
+   The TARGET, TMODE and MODIFIER arguments are as for expand_expr.  */
+
+static rtx
+expand_expr_addr_expr (tree exp, rtx target, enum machine_mode tmode,
+                      enum expand_modifier modifier)
+{
+  rtx result, subtarget;
+  tree inner, offset;
+  HOST_WIDE_INT bitsize, bitpos;
+  int volatilep, unsignedp;
+  enum machine_mode mode1;
+
+  /* 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 call force_const_mem
+     at top level.  */
+  /* ??? This should be considered a front-end bug.  We should not be
+     generating ADDR_EXPR of something that isn't an LVALUE.  The only
+     exception here is STRING_CST.  */
+  if (TREE_CODE (exp) == CONSTRUCTOR
+      || TREE_CODE_CLASS (TREE_CODE (exp)) == 'c')
+    return XEXP (output_constant_def (exp, 0), 0);
+
+  /* Everything must be something allowed by is_gimple_addressable.  */
+  switch (TREE_CODE (exp))
+    {
+    case INDIRECT_REF:
+      /* This case will happen via recursion for &a->b.  */
+      return expand_expr (TREE_OPERAND (exp, 0), target, tmode, EXPAND_NORMAL);
+
+    case CONST_DECL:
+      /* Recurse and make the output_constant_def clause above handle this.  */
+      return expand_expr_addr_expr (DECL_INITIAL (exp), target,
+                                   tmode, modifier);
+
+    case REALPART_EXPR:
+      /* The real part of the complex number is always first, therefore
+        the address is the same as the address of the parent object.  */
+      offset = 0;
+      bitpos = 0;
+      inner = TREE_OPERAND (exp, 0);
+      break;
+
+    case IMAGPART_EXPR:
+      /* The imaginary part of the complex number is always second.
+        The expression is therefore always offset by the size of the
+        scalar type.  */
+      offset = 0;
+      bitpos = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (exp)));
+      inner = TREE_OPERAND (exp, 0);
+      break;
+
+    default:
+      /* If the object is a DECL, then expand it for its rtl.  Don't bypass
+        expand_expr, as that can have various side effects; LABEL_DECLs for
+        example, may not have their DECL_RTL set yet.  Assume language
+        specific tree nodes can be expanded in some interesting way.  */
+      if (DECL_P (exp)
+         || TREE_CODE (exp) >= LAST_AND_UNUSED_TREE_CODE)
+       {
+         result = expand_expr (exp, target, tmode,
+                               modifier == EXPAND_INITIALIZER
+                               ? EXPAND_INITIALIZER : EXPAND_CONST_ADDRESS);
+
+         /* If the DECL isn't in memory, then the DECL wasn't properly
+            marked TREE_ADDRESSABLE, which will be either a front-end
+            or a tree optimizer bug.  */
+         gcc_assert (GET_CODE (result) == MEM);
+         result = XEXP (result, 0);
+
+         /* ??? Is this needed anymore?  */
+         if (!TREE_USED (exp) == 0)
+           {
+             assemble_external (exp);
+             TREE_USED (exp) = 1;
+           }
+
+         if (modifier != EXPAND_INITIALIZER
+             && modifier != EXPAND_CONST_ADDRESS)
+           result = force_operand (result, target);
+         return result;
+       }
+
+      inner = get_inner_reference (exp, &bitsize, &bitpos, &offset,
+                                  &mode1, &unsignedp, &volatilep);
+      break;
+    }
+
+  /* We must have made progress.  */
+  gcc_assert (inner != exp);
+
+  subtarget = offset || bitpos ? NULL_RTX : target;
+  result = expand_expr_addr_expr (inner, subtarget, tmode, modifier);
+
+  if (tmode == VOIDmode)
+    {
+      tmode = GET_MODE (result);
+      if (tmode == VOIDmode)
+       tmode = Pmode;
+    }
+
+  if (offset)
+    {
+      rtx tmp;
+
+      if (modifier != EXPAND_NORMAL)
+       result = force_operand (result, NULL);
+      tmp = expand_expr (offset, NULL, tmode, EXPAND_NORMAL);
+
+      if (modifier == EXPAND_SUM)
+       result = gen_rtx_PLUS (tmode, result, tmp);
+      else
+       {
+         subtarget = bitpos ? NULL_RTX : target;
+         result = expand_simple_binop (tmode, PLUS, result, tmp, subtarget,
+                                       1, OPTAB_LIB_WIDEN);
+       }
+    }
+
+  if (bitpos)
+    {
+      /* Someone beforehand should have rejected taking the address
+        of such an object.  */
+      gcc_assert (!(bitpos % BITS_PER_UNIT));
+
+      result = plus_constant (result, bitpos / BITS_PER_UNIT);
+      if (modifier < EXPAND_SUM)
+       result = force_operand (result, target);
+    }
+
+  return result;
+}
+
 /* expand_expr: generate code for computing expression EXP.
    An rtx for the computed value is returned.  The value is never null.
    In the case of a void EXP, const0_rtx is returned.
@@ -6574,38 +6221,132 @@ find_placeholder (tree exp, tree *plist)
    marked TARGET so that it's safe from being trashed by libcalls.  We
    don't want to use TARGET for anything but the final result;
    Intermediate values must go elsewhere.   Additionally, calls to
-   emit_block_move will be flagged with BLOCK_OP_CALL_PARM.  */
+   emit_block_move will be flagged with BLOCK_OP_CALL_PARM.
+
+   If EXP is a VAR_DECL whose DECL_RTL was a MEM with an invalid
+   address, and ALT_RTL is non-NULL, then *ALT_RTL is set to the
+   DECL_RTL of the VAR_DECL.  *ALT_RTL is also set if EXP is a
+   COMPOUND_EXPR whose second argument is such a VAR_DECL, and so on
+   recursively.  */
+
+static rtx expand_expr_real_1 (tree, rtx, enum machine_mode,
+                              enum expand_modifier, rtx *);
 
 rtx
-expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier modifier)
+expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
+                 enum expand_modifier modifier, rtx *alt_rtl)
+{
+  int rn = -1;
+  rtx ret, last = NULL;
+
+  /* Handle ERROR_MARK before anybody tries to access its type.  */
+  if (TREE_CODE (exp) == ERROR_MARK
+      || TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK)
+    {
+      ret = CONST0_RTX (tmode);
+      return ret ? ret : const0_rtx;
+    }
+
+  if (flag_non_call_exceptions)
+    {
+      rn = lookup_stmt_eh_region (exp);
+      /* If rn < 0, then either (1) tree-ssa not used or (2) doesn't throw.  */
+      if (rn >= 0)
+       last = get_last_insn ();
+    }
+
+  /* If this is an expression of some kind and it has an associated line
+     number, then emit the line number before expanding the expression.
+
+     We need to save and restore the file and line information so that
+     errors discovered during expansion are emitted with the right
+     information.  It would be better of the diagnostic routines
+     used the file/line information embedded in the tree nodes rather
+     than globals.  */
+  if (cfun && EXPR_HAS_LOCATION (exp))
+    {
+      location_t saved_location = input_location;
+      input_location = EXPR_LOCATION (exp);
+      emit_line_note (input_location);
+
+      /* Record where the insns produced belong.  */
+      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
+             && (CALL_P (insn) || may_trap_p (PATTERN (insn))))
+           {
+             REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION, GEN_INT (rn),
+                                                 REG_NOTES (insn));
+           }
+       }
+    }
+
+  return ret;
+}
+
+static rtx
+expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
+                   enum expand_modifier modifier, rtx *alt_rtl)
 {
   rtx op0, op1, temp;
   tree type = TREE_TYPE (exp);
-  int unsignedp = TREE_UNSIGNED (type);
+  int unsignedp;
   enum machine_mode mode;
   enum tree_code code = TREE_CODE (exp);
   optab this_optab;
   rtx subtarget, original_target;
   int ignore;
   tree context;
+  bool reduce_bit_field = false;
+#define REDUCE_BIT_FIELD(expr) (reduce_bit_field && !ignore              \
+                                ? reduce_to_bit_field_precision ((expr), \
+                                                                 target, \
+                                                                 type)   \
+                                : (expr))
 
-  /* 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);
+  if (lang_hooks.reduce_bit_field_operations
+      && TREE_CODE (type) == INTEGER_TYPE
+      && GET_MODE_PRECISION (mode) > TYPE_PRECISION (type))
+    {
+      /* An operation in what may be a bit-field type needs the
+        result to be reduced to the precision of the bit-field type,
+        which is narrower than that of the type's mode.  */
+      reduce_bit_field = true;
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
     }
 
-  mode = TYPE_MODE (type);
   /* Use subtarget as the target for operand 0 of a binary operation.  */
   subtarget = get_subtarget (target);
   original_target = target;
   ignore = (target == const0_rtx
            || ((code == NON_LVALUE_EXPR || code == NOP_EXPR
-                || code == CONVERT_EXPR || code == REFERENCE_EXPR
-                || code == COND_EXPR || code == VIEW_CONVERT_EXPR)
+                || code == CONVERT_EXPR || code == COND_EXPR
+                || code == VIEW_CONVERT_EXPR)
                && TREE_CODE (type) == VOID_TYPE));
 
   /* If we are going to ignore this result, we need only do something
@@ -6627,13 +6368,13 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          && modifier != EXPAND_CONST_ADDRESS)
        {
          temp = expand_expr (exp, NULL_RTX, VOIDmode, modifier);
-         if (GET_CODE (temp) == MEM)
+         if (MEM_P (temp))
            temp = copy_to_reg (temp);
          return const0_rtx;
        }
 
       if (TREE_CODE_CLASS (code) == '1' || code == COMPONENT_REF
-         || code == INDIRECT_REF || code == BUFFER_REF)
+         || code == INDIRECT_REF)
        return expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
                            modifier);
 
@@ -6661,49 +6402,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
@@ -6712,9 +6410,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)
@@ -6722,33 +6420,23 @@ 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);
-         return CONST0_RTX (mode);
-       }
-
-      /* ... fall through ...  */
+    case SSA_NAME:
+      return expand_expr_real_1 (SSA_NAME_VAR (exp), target, tmode, modifier,
+                                NULL);
 
+    case PARM_DECL:
     case VAR_DECL:
       /* If a static var's type was incomplete when the decl was written,
         but the type is complete now, lay out the decl now.  */
@@ -6761,8 +6449,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
 
     case FUNCTION_DECL:
     case RESULT_DECL:
-      if (DECL_RTL (exp) == 0)
-       abort ();
+      gcc_assert (DECL_RTL (exp));
 
       /* Ensure variable marked as used even if it doesn't go through
         a parser.  If it hasn't be used yet, write out an external
@@ -6776,68 +6463,47 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       /* Show we haven't gotten RTL for this yet.  */
       temp = 0;
 
-      /* Handle variables inherited from containing functions.  */
+      /* Variables inherited from containing functions should have
+        been lowered by this point.  */
       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))))
-       {
-         rtx addr;
-
-         /* Mark as non-local and addressable.  */
-         DECL_NONLOCAL (exp) = 1;
-         if (DECL_NO_STATIC_CHAIN (current_function_decl))
-           abort ();
-         (*lang_hooks.mark_addressable) (exp);
-         if (GET_CODE (DECL_RTL (exp)) != MEM)
-           abort ();
-         addr = XEXP (DECL_RTL (exp), 0);
-         if (GET_CODE (addr) == MEM)
-           addr
-             = replace_equiv_address (addr,
-                                      fix_lexical_addr (XEXP (addr, 0), exp));
-         else
-           addr = fix_lexical_addr (addr, exp);
-
-         temp = replace_equiv_address (DECL_RTL (exp), addr);
-       }
+      gcc_assert (!context
+                 || context == current_function_decl
+                 || TREE_STATIC (exp)
+                 /* ??? C++ creates functions that are not TREE_STATIC.  */
+                 || TREE_CODE (exp) == FUNCTION_DECL);
 
       /* This is the case of an array whose size is to be determined
         from its initializer, while the initializer is still being parsed.
         See expand_decl.  */
 
-      else if (GET_CODE (DECL_RTL (exp)) == MEM
-              && GET_CODE (XEXP (DECL_RTL (exp), 0)) == REG)
+      if (MEM_P (DECL_RTL (exp))
+              && 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
         the address is not valid or it is not a register and -fforce-addr
         is specified, get the address into a register.  */
 
-      else if (GET_CODE (DECL_RTL (exp)) == MEM
+      else if (MEM_P (DECL_RTL (exp))
               && modifier != EXPAND_CONST_ADDRESS
               && modifier != EXPAND_SUM
               && modifier != EXPAND_INITIALIZER
               && (! 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 (MEM_P (temp) && REG_P (XEXP (temp, 0)))
            mark_reg_pointer (XEXP (temp, 0), DECL_ALIGN (exp));
 
          return temp;
@@ -6847,15 +6513,16 @@ 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))
        {
+         enum machine_mode pmode;
+         
          /* Get the signedness used for this variable.  Ensure we get the
             same mode we got when the variable was declared.  */
-         if (GET_MODE (DECL_RTL (exp))
-             != promote_mode (type, DECL_MODE (exp), &unsignedp,
-                              (TREE_CODE (exp) == RESULT_DECL ? 1 : 0)))
-           abort ();
+         pmode = promote_mode (type, DECL_MODE (exp), &unsignedp,
+                               (TREE_CODE (exp) == RESULT_DECL ? 1 : 0));
+         gcc_assert (GET_MODE (DECL_RTL (exp)) == pmode);
 
          temp = gen_lowpart_SUBREG (mode, DECL_RTL (exp));
          SUBREG_PROMOTED_VAR_P (temp) = 1;
@@ -6881,7 +6548,13 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       return temp;
 
     case VECTOR_CST:
-      return const_vector_from_tree (exp);
+      if (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) == MODE_VECTOR_INT
+         || GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) == MODE_VECTOR_FLOAT)
+       return const_vector_from_tree (exp);
+      else
+       return expand_expr (build1 (CONSTRUCTOR, TREE_TYPE (exp),
+                                   TREE_VECTOR_CST_ELTS (exp)),
+                           ignore ? const0_rtx : target, tmode, modifier);
 
     case CONST_DECL:
       return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier);
@@ -6939,217 +6612,39 @@ 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);
-
-      /* If this SAVE_EXPR was at global context, assume we are an
-        initialization function and move it into our context.  */
-      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)
-       context = 0;
-
-      /* If this is non-local, handle it.  */
-      if (context)
-       {
-         /* The following call just exists to abort if the context is
-            not of a containing function.  */
-         find_function_data (context);
-
-         temp = SAVE_EXPR_RTL (exp);
-         if (temp && GET_CODE (temp) == REG)
-           {
-             put_var_into_stack (exp, /*rescan=*/true);
-             temp = SAVE_EXPR_RTL (exp);
-           }
-         if (temp == 0 || GET_CODE (temp) != MEM)
-           abort ();
-         return
-           replace_equiv_address (temp,
-                                  fix_lexical_addr (XEXP (temp, 0), exp));
-       }
-      if (SAVE_EXPR_RTL (exp) == 0)
-       {
-         if (mode == VOIDmode)
-           temp = const0_rtx;
-         else
-           temp = assign_temp (build_qualified_type (type,
-                                                     (TYPE_QUALS (type)
-                                                      | TYPE_QUAL_CONST)),
-                               3, 0, 0);
-
-         SAVE_EXPR_RTL (exp) = temp;
-         if (!optimize && GET_CODE (temp) == REG)
-           save_expr_regs = gen_rtx_EXPR_LIST (VOIDmode, temp,
-                                               save_expr_regs);
-
-         /* If the mode of TEMP does not match that of the expression, it
-            must be a promoted value.  We pass store_expr a SUBREG of the
-            wanted mode but mark it so that we know that it was already
-            extended.  */
-
-         if (GET_CODE (temp) == REG && GET_MODE (temp) != mode)
-           {
-             temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
-             promote_mode (type, mode, &unsignedp, 0);
-             SUBREG_PROMOTED_VAR_P (temp) = 1;
-             SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
-           }
-
-         if (temp == const0_rtx)
-           expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
-         else
-           store_expr (TREE_OPERAND (exp, 0), temp,
-                       modifier == EXPAND_STACK_PARM ? 2 : 0);
-
-         TREE_USED (exp) = 1;
-       }
-
-      /* If the mode of SAVE_EXPR_RTL does not match that of the expression, it
-        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
-         && GET_MODE (SAVE_EXPR_RTL (exp)) != mode)
-       {
-         /* Compute the signedness and make the proper SUBREG.  */
-         promote_mode (type, mode, &unsignedp, 0);
-         temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
-         SUBREG_PROMOTED_VAR_P (temp) = 1;
-         SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
-         return temp;
-       }
-
-      return SAVE_EXPR_RTL (exp);
-
-    case UNSAVE_EXPR:
-      {
-       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));
-       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));
-      else
-       expand_computed_goto (TREE_OPERAND (exp, 0));
-      return const0_rtx;
-
-    case EXIT_EXPR:
-      expand_exit_loop_if_false (NULL,
-                                invert_truthvalue (TREE_OPERAND (exp, 0)));
-      return const0_rtx;
-
-    case LABELED_BLOCK_EXPR:
-      if (LABELED_BLOCK_BODY (exp))
-       expand_expr_stmt_value (LABELED_BLOCK_BODY (exp), 0, 1);
-      /* Should perhaps use expand_label, but this is simpler and safer.  */
-      do_pending_stack_adjust ();
-      emit_label (label_rtx (LABELED_BLOCK_LABEL (exp)));
-      return const0_rtx;
-
-    case EXIT_BLOCK_EXPR:
-      if (EXIT_BLOCK_RETURN (exp))
-       sorry ("returned value in block_exit_expr");
-      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);
-
-       /* Need to open a binding contour here because
-          if there are any cleanups they must be contained here.  */
-       expand_start_bindings (2);
-
-       /* 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));
+    case SAVE_EXPR:
+      {
+       tree val = TREE_OPERAND (exp, 0);
+       rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl);
 
-       /* If VARS have not yet been expanded, expand them now.  */
-       while (vars)
+       if (!SAVE_EXPR_RESOLVED_P (exp))
          {
-           if (!DECL_RTL_SET_P (vars))
-             expand_decl (vars);
-           expand_decl_init (vars);
-           vars = TREE_CHAIN (vars);
+           /* We can indeed still hit this case, typically via builtin
+              expanders calling save_expr immediately before expanding
+              something.  Assume this means that we only have to deal
+              with non-BLKmode values.  */
+           gcc_assert (GET_MODE (ret) != BLKmode);
+
+           val = build_decl (VAR_DECL, NULL, TREE_TYPE (exp));
+           DECL_ARTIFICIAL (val) = 1;
+           DECL_IGNORED_P (val) = 1;
+           TREE_OPERAND (exp, 0) = val;
+           SAVE_EXPR_RESOLVED_P (exp) = 1;
+
+           if (!CONSTANT_P (ret))
+             ret = copy_to_reg (ret);
+           SET_DECL_RTL (val, ret);
          }
 
-       temp = expand_expr (TREE_OPERAND (exp, 1), target, tmode, modifier);
-
-       expand_end_bindings (TREE_OPERAND (exp, 0), 0, 0);
-
-       return temp;
+        return ret;
       }
 
-    case RTL_EXPR:
-      if (RTL_EXPR_SEQUENCE (exp))
-       {
-         if (RTL_EXPR_SEQUENCE (exp) == const0_rtx)
-           abort ();
-         emit_insn (RTL_EXPR_SEQUENCE (exp));
-         RTL_EXPR_SEQUENCE (exp) = const0_rtx;
-       }
-      preserve_rtl_expr_result (RTL_EXPR_RTL (exp));
-      free_temps_for_rtl_expr (exp);
-      return RTL_EXPR_RTL (exp);
+    case GOTO_EXPR:
+      if (TREE_CODE (TREE_OPERAND (exp, 0)) == LABEL_DECL)
+       expand_goto (TREE_OPERAND (exp, 0));
+      else
+       expand_computed_goto (TREE_OPERAND (exp, 0));
+      return const0_rtx;
 
     case CONSTRUCTOR:
       /* If we don't need the result, just ensure we evaluate any
@@ -7185,9 +6680,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)))
@@ -7222,45 +6715,39 @@ 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);
+       tree orig;
 
-       /* 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);
        temp = gen_rtx_MEM (mode, op0);
-       set_mem_attributes (temp, exp, 0);
 
-       /* If we are writing to this object and its type is a record with
-          readonly fields, we must mark it as readonly so it will
-          conflict with readonly references to those fields.  */
-       if (modifier == EXPAND_WRITE && readonly_fields_p (type))
-         RTX_UNCHANGING_P (temp) = 1;
+       orig = REF_ORIGINAL (exp);
+       if (!orig)
+         orig = exp;
+       set_mem_attributes (temp, orig, 0);
 
        return temp;
       }
 
     case ARRAY_REF:
-      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) != ARRAY_TYPE)
-       abort ();
 
       {
        tree array = TREE_OPERAND (exp, 0);
-       tree domain = TYPE_DOMAIN (TREE_TYPE (array));
-       tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
+       tree low_bound = array_ref_low_bound (exp);
        tree index = convert (sizetype, TREE_OPERAND (exp, 1));
        HOST_WIDE_INT i;
 
+       gcc_assert (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE);
+
        /* Optimize the special-case of a zero lower bound.
 
           We convert the low_bound to sizetype to avoid some problems
@@ -7279,14 +6766,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
@@ -7321,7 +6807,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)
              {
@@ -7392,7 +6879,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);
@@ -7400,8 +6887,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                    else
                      {
                        tree count
-                         = build_int_2 (GET_MODE_BITSIZE (imode) - bitsize,
-                                        0);
+                         = build_int_cst (NULL_TREE,
+                                          GET_MODE_BITSIZE (imode) - bitsize);
 
                        op0 = expand_shift (LSHIFT_EXPR, imode, op0, count,
                                            target, 0);
@@ -7430,8 +6917,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        /* If we got back the original object, something is wrong.  Perhaps
           we are evaluating an expression too early.  In any event, don't
           infinitely recurse.  */
-       if (tem == exp)
-         abort ();
+       gcc_assert (tem != exp);
 
        /* If TEM's type is a union of variable size, pass TARGET to the inner
           computation, since it will need a temporary and TARGET is known
@@ -7467,29 +6953,17 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
           C, but can in Ada if we have unchecked conversion of an expression
           from a scalar type to an array or record type or for an
           ARRAY_RANGE_REF whose type is BLKmode.  */
-       else if (GET_CODE (op0) != MEM
+       else if (!MEM_P (op0)
                 && (offset != 0
                     || (code == ARRAY_RANGE_REF && mode == BLKmode)))
          {
-           /* If the operand is a SAVE_EXPR, we can deal with this by
-              forcing the SAVE_EXPR into memory.  */
-           if (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR)
-             {
-               put_var_into_stack (TREE_OPERAND (exp, 0),
-                                   /*rescan=*/true);
-               op0 = SAVE_EXPR_RTL (TREE_OPERAND (exp, 0));
-             }
-           else
-             {
-               tree nt
-                 = build_qualified_type (TREE_TYPE (tem),
-                                         (TYPE_QUALS (TREE_TYPE (tem))
-                                          | TYPE_QUAL_CONST));
-               rtx memloc = assign_temp (nt, 1, 1, 1);
-               
-               emit_move_insn (memloc, op0);
-               op0 = memloc;
-             }
+           tree nt = build_qualified_type (TREE_TYPE (tem),
+                                           (TYPE_QUALS (TREE_TYPE (tem))
+                                            | TYPE_QUAL_CONST));
+           rtx memloc = assign_temp (nt, 1, 1, 1);
+
+           emit_move_insn (memloc, op0);
+           op0 = memloc;
          }
 
        if (offset != 0)
@@ -7497,8 +6971,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
            rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode,
                                          EXPAND_SUM);
 
-           if (GET_CODE (op0) != MEM)
-             abort ();
+           gcc_assert (MEM_P (op0));
 
 #ifdef POINTERS_EXTEND_UNSIGNED
            if (GET_MODE (offset_rtx) != Pmode)
@@ -7508,10 +6981,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
@@ -7528,12 +7000,12 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
 
        /* If OFFSET is making OP0 more aligned than BIGGEST_ALIGNMENT,
           record its alignment as BIGGEST_ALIGNMENT.  */
-       if (GET_CODE (op0) == MEM && bitpos == 0 && offset != 0
+       if (MEM_P (op0) && bitpos == 0 && offset != 0
            && is_aligning_offset (offset, tem))
          set_mem_align (op0, BIGGEST_ALIGNMENT);
 
        /* Don't forget about volatility even if this is a bitfield.  */
-       if (GET_CODE (op0) == MEM && volatilep && ! MEM_VOLATILE_P (op0))
+       if (MEM_P (op0) && volatilep && ! MEM_VOLATILE_P (op0))
          {
            if (op0 == orig_op0)
              op0 = copy_rtx (op0);
@@ -7546,8 +7018,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
           one element arrays having the same mode as its element.  */
        if (GET_CODE (op0) == CONCAT)
          {
-           if (bitpos != 0 || bitsize != GET_MODE_BITSIZE (GET_MODE (op0)))
-             abort ();
+           gcc_assert (bitpos == 0
+                       && bitsize == GET_MODE_BITSIZE (GET_MODE (op0)));
            return op0;
          }
 
@@ -7558,7 +7030,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
@@ -7568,7 +7040,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)
+                     || (MEM_P (op0)
+                         && (MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode1)
+                             || (bitpos % GET_MODE_ALIGNMENT (mode1) != 0))))
                     && ((modifier == EXPAND_CONST_ADDRESS
                          || modifier == EXPAND_INITIALIZER)
                         ? STRICT_ALIGNMENT
@@ -7578,33 +7053,36 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
               size of the type isn't the same size as the bitfield,
               we must use bitfield operations.  */
            || (bitsize >= 0
-               && (TREE_CODE (TYPE_SIZE (TREE_TYPE (exp)))
-                   == INTEGER_CST)
+               && TYPE_SIZE (TREE_TYPE (exp))
+               && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
                && 0 != compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)),
                                          bitsize)))
          {
            enum machine_mode ext_mode = mode;
 
            if (ext_mode == BLKmode
-               && ! (target != 0 && GET_CODE (op0) == MEM
-                     && GET_CODE (target) == MEM
+               && ! (target != 0 && MEM_P (op0)
+                     && MEM_P (target)
                      && bitpos % BITS_PER_UNIT == 0))
              ext_mode = mode_for_size (bitsize, MODE_INT, 1);
 
            if (ext_mode == BLKmode)
              {
-               /* In this case, BITPOS must start at a byte boundary and
-                  TARGET, if specified, must be a MEM.  */
-               if (GET_CODE (op0) != MEM
-                   || (target != 0 && GET_CODE (target) != MEM)
-                   || 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,
+               if (bitsize == 0)
+                 return target;
+
+               /* In this case, BITPOS must start at a byte boundary and
+                  TARGET, if specified, must be a MEM.  */
+               gcc_assert (MEM_P (op0)
+                           && (!target || MEM_P (target))
+                           && !(bitpos % BITS_PER_UNIT));
+
+               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
@@ -7615,14 +7093,13 @@ 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 (MEM_P (op0) && REG_P (XEXP (op0, 0)))
              mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
 
            op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp,
                                     (modifier == EXPAND_STACK_PARM
                                      ? NULL_RTX : target),
-                                    ext_mode, ext_mode,
-                                    int_size_in_bytes (TREE_TYPE (tem)));
+                                    ext_mode, ext_mode);
 
            /* If the result is a record type and BITSIZE is narrower than
               the mode of OP0, an integral mode, and this is a big endian
@@ -7635,12 +7112,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);
@@ -7667,7 +7151,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;
@@ -7682,179 +7166,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        return target;
       }
 
-    case VTABLE_REF:
-      {
-       rtx insn, before = get_last_insn (), vtbl_ref;
-
-       /* Evaluate the interior expression.  */
-       subtarget = expand_expr (TREE_OPERAND (exp, 0), target,
-                                tmode, modifier);
-
-       /* Get or create an instruction off which to hang a note.  */
-       if (REG_P (subtarget))
-         {
-           target = subtarget;
-           insn = get_last_insn ();
-           if (insn == before)
-             abort ();
-           if (! INSN_P (insn))
-             insn = prev_nonnote_insn (insn);
-         }
-       else
-         {
-           target = gen_reg_rtx (GET_MODE (subtarget));
-           insn = emit_move_insn (target, subtarget);
-         }
-
-       /* Collect the data for the note.  */
-       vtbl_ref = XEXP (DECL_RTL (TREE_OPERAND (exp, 1)), 0);
-       vtbl_ref = plus_constant (vtbl_ref,
-                                 tree_low_cst (TREE_OPERAND (exp, 2), 0));
-       /* Discard the initial CONST that was added.  */
-       vtbl_ref = XEXP (vtbl_ref, 0);
-
-       REG_NOTES (insn)
-         = gen_rtx_EXPR_LIST (REG_VTABLE_REF, vtbl_ref, REG_NOTES (insn));
-
-       return target;
-      }
-
-      /* Intended for a reference to a buffer of a file-object in Pascal.
-        But it's not certain that a special tree code will really be
-        necessary for these.  INDIRECT_REF might work for them.  */
-    case BUFFER_REF:
-      abort ();
-
-    case IN_EXPR:
-      {
-       /* Pascal set IN expression.
-
-          Algorithm:
-              rlo       = set_low - (set_low%bits_per_word);
-              the_word  = set [ (index - rlo)/bits_per_word ];
-              bit_index = index % bits_per_word;
-              bitmask   = 1 << bit_index;
-              return !!(the_word & bitmask);  */
-
-       tree set = TREE_OPERAND (exp, 0);
-       tree index = TREE_OPERAND (exp, 1);
-       int iunsignedp = TREE_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));
-       rtx index_val = expand_expr (index, 0, VOIDmode, 0);
-       rtx lo_r = expand_expr (set_low_bound, 0, VOIDmode, 0);
-       rtx hi_r = expand_expr (set_high_bound, 0, VOIDmode, 0);
-       rtx setval = expand_expr (set, 0, VOIDmode, 0);
-       rtx setaddr = XEXP (setval, 0);
-       enum machine_mode index_mode = TYPE_MODE (TREE_TYPE (index));
-       rtx rlow;
-       rtx diff, quo, rem, addr, bit, result;
-
-       /* If domain is empty, answer is no.  Likewise if index is constant
-          and out of bounds.  */
-       if (((TREE_CODE (set_high_bound) == INTEGER_CST
-            && TREE_CODE (set_low_bound) == INTEGER_CST
-            && tree_int_cst_lt (set_high_bound, set_low_bound))
-            || (TREE_CODE (index) == INTEGER_CST
-                && TREE_CODE (set_low_bound) == INTEGER_CST
-                && tree_int_cst_lt (index, set_low_bound))
-            || (TREE_CODE (set_high_bound) == INTEGER_CST
-                && TREE_CODE (index) == INTEGER_CST
-                && tree_int_cst_lt (set_high_bound, index))))
-         return const0_rtx;
-
-       if (target == 0)
-         target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
-
-       /* If we get here, we have to generate the code for both cases
-          (in range and out of range).  */
-
-       op0 = gen_label_rtx ();
-       op1 = gen_label_rtx ();
-
-       if (! (GET_CODE (index_val) == CONST_INT
-              && GET_CODE (lo_r) == CONST_INT))
-         emit_cmp_and_jump_insns (index_val, lo_r, LT, NULL_RTX,
-                                  GET_MODE (index_val), iunsignedp, op1);
-
-       if (! (GET_CODE (index_val) == CONST_INT
-              && GET_CODE (hi_r) == CONST_INT))
-         emit_cmp_and_jump_insns (index_val, hi_r, GT, NULL_RTX,
-                                  GET_MODE (index_val), iunsignedp, op1);
-
-       /* Calculate the element number of bit zero in the first word
-          of the set.  */
-       if (GET_CODE (lo_r) == CONST_INT)
-         rlow = GEN_INT (INTVAL (lo_r)
-                         & ~((HOST_WIDE_INT) 1 << BITS_PER_UNIT));
-       else
-         rlow = expand_binop (index_mode, and_optab, lo_r,
-                              GEN_INT (~((HOST_WIDE_INT) 1 << BITS_PER_UNIT)),
-                              NULL_RTX, iunsignedp, OPTAB_LIB_WIDEN);
-
-       diff = expand_binop (index_mode, sub_optab, index_val, rlow,
-                            NULL_RTX, iunsignedp, OPTAB_LIB_WIDEN);
-
-       quo = expand_divmod (0, TRUNC_DIV_EXPR, index_mode, diff,
-                            GEN_INT (BITS_PER_UNIT), NULL_RTX, iunsignedp);
-       rem = expand_divmod (1, TRUNC_MOD_EXPR, index_mode, index_val,
-                            GEN_INT (BITS_PER_UNIT), NULL_RTX, iunsignedp);
-
-       addr = memory_address (byte_mode,
-                              expand_binop (index_mode, add_optab, diff,
-                                            setaddr, NULL_RTX, iunsignedp,
-                                            OPTAB_LIB_WIDEN));
-
-       /* Extract the bit we want to examine.  */
-       bit = expand_shift (RSHIFT_EXPR, byte_mode,
-                           gen_rtx_MEM (byte_mode, addr),
-                           make_tree (TREE_TYPE (index), rem),
-                           NULL_RTX, 1);
-       result = expand_binop (byte_mode, and_optab, bit, const1_rtx,
-                              GET_MODE (target) == byte_mode ? target : 0,
-                              1, OPTAB_LIB_WIDEN);
-
-       if (result != target)
-         convert_move (target, result, 1);
-
-       /* Output the code to handle the out-of-range case.  */
-       emit_jump (op0);
-       emit_label (op1);
-       emit_move_insn (target, const0_rtx);
-       emit_label (op0);
-       return target;
-      }
-
-    case WITH_CLEANUP_EXPR:
-      if (WITH_CLEANUP_EXPR_RTL (exp) == 0)
-       {
-         WITH_CLEANUP_EXPR_RTL (exp)
-           = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
-         expand_decl_cleanup_eh (NULL_TREE, TREE_OPERAND (exp, 1),
-                                 CLEANUP_EH_ONLY (exp));
-
-         /* That's it for this cleanup.  */
-         TREE_OPERAND (exp, 1) = 0;
-       }
-      return WITH_CLEANUP_EXPR_RTL (exp);
-
-    case CLEANUP_POINT_EXPR:
-      {
-       /* Start a new binding layer that will keep track of all cleanup
-          actions to be performed.  */
-       expand_start_bindings (2);
-
-       target_temp_slot_level = temp_slot_level;
-
-       op0 = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
-       /* If we're going to use this value, load it up now.  */
-       if (! ignore)
-         op0 = force_not_mem (op0);
-       preserve_temp_slots (op0);
-       expand_end_bindings (NULL_TREE, 0, 0);
-      }
-      return op0;
+    case OBJ_TYPE_REF:
+      return expand_expr (OBJ_TYPE_REF_EXPR (exp), target, tmode, modifier);
 
     case CALL_EXPR:
       /* Check for a built-in function.  */
@@ -7865,8 +7178,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);
        }
@@ -7876,7 +7190,6 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
     case NON_LVALUE_EXPR:
     case NOP_EXPR:
     case CONVERT_EXPR:
-    case REFERENCE_EXPR:
       if (TREE_OPERAND (exp, 0) == error_mark_node)
        return const0_rtx;
 
@@ -7897,25 +7210,32 @@ 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)
+         if (MEM_P (target))
            /* Store data into beginning of memory target.  */
            store_expr (TREE_OPERAND (exp, 0),
                        adjust_address (target, TYPE_MODE (valtype), 0),
                        modifier == EXPAND_STACK_PARM ? 2 : 0);
 
-         else if (GET_CODE (target) == REG)
-           /* Store this field into a union of the proper type.  */
-           store_field (target,
-                        MIN ((int_size_in_bytes (TREE_TYPE
-                                                 (TREE_OPERAND (exp, 0)))
-                              * BITS_PER_UNIT),
-                             (HOST_WIDE_INT) GET_MODE_BITSIZE (mode)),
-                        0, TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
-                        VOIDmode, 0, type, 0);
          else
-           abort ();
+           {
+             gcc_assert (REG_P (target));
+             
+             /* Store this field into a union of the proper type.  */
+             store_field (target,
+                          MIN ((int_size_in_bytes (TREE_TYPE
+                                                   (TREE_OPERAND (exp, 0)))
+                                * BITS_PER_UNIT),
+                               (HOST_WIDE_INT) GET_MODE_BITSIZE (mode)),
+                          0, TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
+                          VOIDmode, 0, type, 0);
+           }
 
          /* Return the entire union.  */
          return target;
@@ -7929,14 +7249,15 @@ 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;
 
-         return op0;
+         return REDUCE_BIT_FIELD (op0);
        }
 
       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
+      op0 = REDUCE_BIT_FIELD (op0);
       if (GET_MODE (op0) == mode)
        return op0;
 
@@ -7952,7 +7273,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)
@@ -7961,10 +7282,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:
@@ -7982,7 +7303,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
               && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_WORD
               && GET_MODE_SIZE (GET_MODE (op0)) <= UNITS_PER_WORD)
        op0 = gen_lowpart (TYPE_MODE (type), op0);
-      else if (GET_CODE (op0) != MEM)
+      else if (!MEM_P (op0))
        {
          /* If the operand is not a MEM, force it into memory.  Since we
             are going to be be changing the mode of the MEM, don't call
@@ -7990,8 +7311,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
             constants to change mode.  */
          tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
 
-         if (TREE_ADDRESSABLE (exp))
-           abort ();
+         gcc_assert (!TREE_ADDRESSABLE (exp));
 
          if (target == 0 || GET_MODE (target) != TYPE_MODE (inner_type))
            target
@@ -8007,7 +7327,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
         that the operand is known to be aligned, indicate that it is.
         Otherwise, we need only be concerned about alignment for non-BLKmode
         results.  */
-      if (GET_CODE (op0) == MEM)
+      if (MEM_P (op0))
        {
          op0 = copy_rtx (op0);
 
@@ -8024,8 +7344,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                                                    temp_size, 0, type);
              rtx new_with_op0_mode = adjust_address (new, GET_MODE (op0), 0);
 
-             if (TREE_ADDRESSABLE (exp))
-               abort ();
+             gcc_assert (!TREE_ADDRESSABLE (exp));
 
              if (GET_MODE (op0) == BLKmode)
                emit_block_move (new_with_op0_mode, op0,
@@ -8044,11 +7363,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       return op0;
 
     case PLUS_EXPR:
-      this_optab = ! unsignedp && flag_trapv
-                   && (GET_MODE_CLASS (mode) == MODE_INT)
-                   ? addv_optab : add_optab;
-
-      /* If we are adding a constant, an RTL_EXPR that is sp, fp, or ap, and
+      /* If we are adding a constant, a VAR_DECL that is sp, fp, or ap, and
         something else, make sure we add the register to the constant and
         then to the other thing.  This case can occur during strength
         reduction and doing it this way will produce better code if the
@@ -8061,10 +7376,10 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
 
       if (TREE_CODE (TREE_OPERAND (exp, 0)) == PLUS_EXPR
          && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 1)) == INTEGER_CST
-         && TREE_CODE (TREE_OPERAND (exp, 1)) == RTL_EXPR
-         && (RTL_EXPR_RTL (TREE_OPERAND (exp, 1)) == frame_pointer_rtx
-             || RTL_EXPR_RTL (TREE_OPERAND (exp, 1)) == stack_pointer_rtx
-             || RTL_EXPR_RTL (TREE_OPERAND (exp, 1)) == arg_pointer_rtx))
+         && TREE_CODE (TREE_OPERAND (exp, 1)) == VAR_DECL
+         && (DECL_RTL (TREE_OPERAND (exp, 1)) == frame_pointer_rtx
+             || DECL_RTL (TREE_OPERAND (exp, 1)) == stack_pointer_rtx
+             || DECL_RTL (TREE_OPERAND (exp, 1)) == arg_pointer_rtx))
        {
          tree t = TREE_OPERAND (exp, 1);
 
@@ -8104,7 +7419,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
              op1 = plus_constant (op1, INTVAL (constant_part));
              if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
                op1 = force_operand (op1, target);
-             return op1;
+             return REDUCE_BIT_FIELD (op1);
            }
 
          else if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
@@ -8120,11 +7435,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
@@ -8137,13 +7452,10 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
              op0 = plus_constant (op0, INTVAL (constant_part));
              if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
                op0 = force_operand (op0, target);
-             return op0;
+             return REDUCE_BIT_FIELD (op0);
            }
        }
 
-      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
@@ -8151,12 +7463,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)
@@ -8164,62 +7472,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 REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
 
     case MINUS_EXPR:
       /* For initializers, we are allowed to return a MINUS of two
@@ -8231,23 +7486,17 @@ 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.  */
          if (GET_CODE (op1) == CONST_INT)
-           return plus_constant (op0, - INTVAL (op1));
+           return REDUCE_BIT_FIELD (plus_constant (op0, - INTVAL (op1)));
          else
-           return gen_rtx_MINUS (mode, op0, op1);
+           return REDUCE_BIT_FIELD (gen_rtx_MINUS (mode, op0, op1));
        }
 
-      this_optab = ! unsignedp && flag_trapv
-                   && (GET_MODE_CLASS(mode) == MODE_INT)
-                   ? subv_optab : sub_optab;
-
       /* 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
@@ -8256,17 +7505,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 REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
        }
 
       goto binop2;
@@ -8293,29 +7539,16 @@ 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,
+         return REDUCE_BIT_FIELD (gen_rtx_MULT (mode, op0,
                               gen_int_mode (tree_low_cst (exp1, 0),
-                                            TYPE_MODE (TREE_TYPE (exp1))));
+                                            TYPE_MODE (TREE_TYPE (exp1)))));
        }
 
-      if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
-       subtarget = 0;
-
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
 
@@ -8336,39 +7569,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);
-                 goto binop2;
+                   expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
+                                    TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
+                                    NULL_RTX, &op0, &op1, 0);
+                 goto binop3;
                }
              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)
@@ -8381,38 +7618,32 @@ 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);
-                 return temp;
+                 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 REDUCE_BIT_FIELD (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;
-      return expand_mult (mode, op0, op1, target, unsignedp);
+      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                      subtarget, &op0, &op1, 0);
+      return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp));
 
     case TRUNC_DIV_EXPR:
     case FLOOR_DIV_EXPR:
     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:
@@ -8422,30 +7653,28 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       if (flag_unsafe_math_optimizations && optimize && !optimize_size
          && TREE_CODE (type) == REAL_TYPE
          && !real_onep (TREE_OPERAND (exp, 0)))
-        return expand_expr (build (MULT_EXPR, type, TREE_OPERAND (exp, 0),
-                                  build (RDIV_EXPR, type,
-                                         build_real (type, dconst1),
-                                         TREE_OPERAND (exp, 1))),
+        return expand_expr (build2 (MULT_EXPR, type, TREE_OPERAND (exp, 0),
+                                   build2 (RDIV_EXPR, type,
+                                           build_real (type, dconst1),
+                                           TREE_OPERAND (exp, 1))),
                            target, tmode, modifier);
-      this_optab = sdiv_optab;
+
       goto binop;
 
     case TRUNC_MOD_EXPR:
     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:
     case FIX_FLOOR_EXPR:
     case FIX_CEIL_EXPR:
-      abort ();                        /* Not used for C.  */
+      gcc_unreachable ();                      /* Not used for C.  */
 
     case FIX_TRUNC_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
@@ -8464,7 +7693,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:
@@ -8472,12 +7701,10 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
       temp = expand_unop (mode,
-                         ! unsignedp && flag_trapv
-                         && (GET_MODE_CLASS(mode) == MODE_INT)
-                         ? negv_optab : neg_optab, op0, target, 0);
-      if (temp == 0)
-       abort ();
-      return temp;
+                         optab_for_tree_code (NEGATE_EXPR, type),
+                         op0, target, 0);
+      gcc_assert (temp);
+      return REDUCE_BIT_FIELD (temp);
 
     case ABS_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
@@ -8485,13 +7712,12 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        target = 0;
 
       /* ABS_EXPR is not valid for complex arguments.  */
-      if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
-         || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
-       abort ();
+      gcc_assert (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
+                 && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT);
 
       /* 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,
@@ -8502,22 +7728,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))
+         || (MEM_P (target) && 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)
-                   ? (code == MIN_EXPR ? umin_optab : umax_optab)
-                   : (code == MIN_EXPR ? smin_optab : smax_optab));
-
+      this_optab = optab_for_tree_code (code, type);
       temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
                           OPTAB_WIDEN);
       if (temp != 0)
@@ -8526,9 +7748,17 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       /* At this point, a MEM target is no longer useful; we will get better
         code without it.  */
 
-      if (GET_CODE (target) == MEM)
+      if (MEM_P (target))
        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);
 
@@ -8540,18 +7770,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);
@@ -8562,45 +7790,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
       temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
-      if (temp == 0)
-       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 ();
+      gcc_assert (temp);
       return temp;
 
       /* ??? Can optimize bitwise operations with one arg constant.
@@ -8617,18 +7807,18 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
         how to recognize those cases.  */
 
     case TRUTH_AND_EXPR:
+      code = BIT_AND_EXPR;
     case BIT_AND_EXPR:
-      this_optab = and_optab;
       goto binop;
 
     case TRUTH_OR_EXPR:
+      code = BIT_IOR_EXPR;
     case BIT_IOR_EXPR:
-      this_optab = ior_optab;
       goto binop;
 
     case TRUTH_XOR_EXPR:
+      code = BIT_XOR_EXPR;
     case BIT_XOR_EXPR:
-      this_optab = xor_optab;
       goto binop;
 
     case LSHIFT_EXPR:
@@ -8658,6 +7848,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);
@@ -8667,7 +7858,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)))))
        {
@@ -8680,475 +7871,138 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
              if (INTVAL (temp) != 0)
                emit_move_insn (target, const1_rtx);
              else
-               emit_move_insn (target, const0_rtx);
-
-             return target;
-           }
-
-         if (temp != original_target)
-           {
-             enum machine_mode mode1 = GET_MODE (temp);
-             if (mode1 == VOIDmode)
-               mode1 = tmode != VOIDmode ? tmode : mode;
-
-             temp = copy_to_mode_reg (mode1, temp);
-           }
-
-         op1 = gen_label_rtx ();
-         emit_cmp_and_jump_insns (temp, const0_rtx, EQ, NULL_RTX,
-                                  GET_MODE (temp), unsignedp, op1);
-         emit_move_insn (temp, const1_rtx);
-         emit_label (op1);
-         return temp;
-       }
-
-      /* If no set-flag instruction, must generate a conditional
-        store into a temporary variable.  Drop through
-        and handle this like && and ||.  */
-
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-      if (! ignore
-         && (target == 0
-             || modifier == EXPAND_STACK_PARM
-             || ! 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
-                 && REGNO (target) < FIRST_PSEUDO_REGISTER)))
-       target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
-
-      if (target)
-       emit_clr_insn (target);
-
-      op1 = gen_label_rtx ();
-      jumpifnot (exp, op1);
-
-      if (target)
-       emit_0_to_1_insn (target);
-
-      emit_label (op1);
-      return ignore ? const0_rtx : target;
-
-    case TRUTH_NOT_EXPR:
-      if (modifier == EXPAND_STACK_PARM)
-       target = 0;
-      op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
-      /* The parser is careful to generate TRUTH_NOT_EXPR
-        only with operands that are always zero or one.  */
-      temp = expand_binop (mode, xor_optab, op0, const1_rtx,
-                          target, 1, OPTAB_LIB_WIDEN);
-      if (temp == 0)
-       abort ();
-      return temp;
-
-    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);
-
-    case COND_EXPR:
-      /* 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
-         && TREE_CODE (TREE_OPERAND (exp, 2)) == NOP_EXPR
-         && (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0))
-             == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 2), 0))))
-       {
-         tree iftrue = TREE_OPERAND (TREE_OPERAND (exp, 1), 0);
-         tree iffalse = TREE_OPERAND (TREE_OPERAND (exp, 2), 0);
-
-         if ((TREE_CODE_CLASS (TREE_CODE (iftrue)) == '2'
-              && operand_equal_p (iffalse, TREE_OPERAND (iftrue, 0), 0))
-             || (TREE_CODE_CLASS (TREE_CODE (iffalse)) == '2'
-                 && operand_equal_p (iftrue, TREE_OPERAND (iffalse, 0), 0))
-             || (TREE_CODE_CLASS (TREE_CODE (iftrue)) == '1'
-                 && operand_equal_p (iffalse, TREE_OPERAND (iftrue, 0), 0))
-             || (TREE_CODE_CLASS (TREE_CODE (iffalse)) == '1'
-                 && operand_equal_p (iftrue, TREE_OPERAND (iffalse, 0), 0)))
-           return expand_expr (build1 (NOP_EXPR, type,
-                                       build (COND_EXPR, TREE_TYPE (iftrue),
-                                              TREE_OPERAND (exp, 0),
-                                              iftrue, iffalse)),
-                               target, tmode, modifier);
-       }
-
-      {
-       /* Note that COND_EXPRs whose type is a structure or union
-          are required to be constructed to contain assignments of
-          a temporary variable, so that we can evaluate them here
-          for side effect only.  If type is void, we must do likewise.  */
-
-       /* If an arm of the branch requires a cleanup,
-          only that cleanup is performed.  */
-
-       tree singleton = 0;
-       tree binary_op = 0, unary_op = 0;
-
-       /* If this is (A ? 1 : 0) and A is a condition, just evaluate it and
-          convert it to our mode, if necessary.  */
-       if (integer_onep (TREE_OPERAND (exp, 1))
-           && integer_zerop (TREE_OPERAND (exp, 2))
-           && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
-         {
-           if (ignore)
-             {
-               expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
-                            modifier);
-               return const0_rtx;
-             }
-
-           if (modifier == EXPAND_STACK_PARM)
-             target = 0;
-           op0 = expand_expr (TREE_OPERAND (exp, 0), target, mode, modifier);
-           if (GET_MODE (op0) == mode)
-             return op0;
-
-           if (target == 0)
-             target = gen_reg_rtx (mode);
-           convert_move (target, op0, unsignedp);
-           return target;
-         }
-
-       /* Check for X ? A + B : A.  If we have this, we can copy A to the
-          output and conditionally add B.  Similarly for unary operations.
-          Don't do this if X has side-effects because those side effects
-          might affect A or B and the "?" operation is a sequence point in
-          ANSI.  (operand_equal_p tests for side effects.)  */
-
-       if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 1))) == '2'
-           && operand_equal_p (TREE_OPERAND (exp, 2),
-                               TREE_OPERAND (TREE_OPERAND (exp, 1), 0), 0))
-         singleton = TREE_OPERAND (exp, 2), binary_op = TREE_OPERAND (exp, 1);
-       else if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 2))) == '2'
-                && operand_equal_p (TREE_OPERAND (exp, 1),
-                                    TREE_OPERAND (TREE_OPERAND (exp, 2), 0), 0))
-         singleton = TREE_OPERAND (exp, 1), binary_op = TREE_OPERAND (exp, 2);
-       else if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 1))) == '1'
-                && operand_equal_p (TREE_OPERAND (exp, 2),
-                                    TREE_OPERAND (TREE_OPERAND (exp, 1), 0), 0))
-         singleton = TREE_OPERAND (exp, 2), unary_op = TREE_OPERAND (exp, 1);
-       else if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 2))) == '1'
-                && operand_equal_p (TREE_OPERAND (exp, 1),
-                                    TREE_OPERAND (TREE_OPERAND (exp, 2), 0), 0))
-         singleton = TREE_OPERAND (exp, 1), unary_op = TREE_OPERAND (exp, 2);
-
-       /* If we are not to produce a result, we have no target.  Otherwise,
-          if a target was specified use it; it will not be used as an
-          intermediate target unless it is safe.  If no target, use a
-          temporary.  */
-
-       if (ignore)
-         temp = 0;
-       else if (modifier == EXPAND_STACK_PARM)
-         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
-                        && 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
-                    || TREE_ADDRESSABLE (type))
-#endif
-                && (GET_CODE (original_target) != MEM
-                    || TREE_ADDRESSABLE (type)))
-         temp = original_target;
-       else if (TREE_ADDRESSABLE (type))
-         abort ();
-       else
-         temp = assign_temp (type, 0, 0, 1);
-
-       /* If we had X ? A + C : A, with C a constant power of 2, and we can
-          do the test of X as a store-flag operation, do this as
-          A + ((X != 0) << log C).  Similarly for other simple binary
-          operators.  Only do for C == 1 if BRANCH_COST is low.  */
-       if (temp && singleton && binary_op
-           && (TREE_CODE (binary_op) == PLUS_EXPR
-               || TREE_CODE (binary_op) == MINUS_EXPR
-               || TREE_CODE (binary_op) == BIT_IOR_EXPR
-               || TREE_CODE (binary_op) == BIT_XOR_EXPR)
-           && (BRANCH_COST >= 3 ? integer_pow2p (TREE_OPERAND (binary_op, 1))
-               : integer_onep (TREE_OPERAND (binary_op, 1)))
-           && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
-         {
-           rtx result;
-           tree cond;
-           optab boptab = (TREE_CODE (binary_op) == PLUS_EXPR
-                           ? (TYPE_TRAP_SIGNED (TREE_TYPE (binary_op))
-                              ? addv_optab : add_optab)
-                           : TREE_CODE (binary_op) == MINUS_EXPR
-                           ? (TYPE_TRAP_SIGNED (TREE_TYPE (binary_op))
-                              ? subv_optab : sub_optab)
-                           : TREE_CODE (binary_op) == BIT_IOR_EXPR ? ior_optab
-                           : xor_optab);
-
-           /* If we had X ? A : A + 1, do this as A + (X == 0).  */
-           if (singleton == TREE_OPERAND (exp, 1))
-             cond = invert_truthvalue (TREE_OPERAND (exp, 0));
-           else
-             cond = TREE_OPERAND (exp, 0);
-
-           result = do_store_flag (cond, (safe_from_p (temp, singleton, 1)
-                                          ? temp : NULL_RTX),
-                                   mode, BRANCH_COST <= 1);
-
-           if (result != 0 && ! integer_onep (TREE_OPERAND (binary_op, 1)))
-             result = expand_shift (LSHIFT_EXPR, mode, result,
-                                    build_int_2 (tree_log2
-                                                 (TREE_OPERAND
-                                                  (binary_op, 1)),
-                                                 0),
-                                    (safe_from_p (temp, singleton, 1)
-                                     ? temp : NULL_RTX), 0);
-
-           if (result)
-             {
-               op1 = expand_expr (singleton, NULL_RTX, VOIDmode, 0);
-               return expand_binop (mode, boptab, op1, result, temp,
-                                    unsignedp, OPTAB_LIB_WIDEN);
-             }
-         }
-
-       do_pending_stack_adjust ();
-       NO_DEFER_POP;
-       op0 = gen_label_rtx ();
-
-       if (singleton && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0)))
-         {
-           if (temp != 0)
-             {
-               /* If the target conflicts with the other operand of the
-                  binary op, we can't use it.  Also, we can't use the target
-                  if it is a hard register, because evaluating the condition
-                  might clobber it.  */
-               if ((binary_op
-                    && ! safe_from_p (temp, TREE_OPERAND (binary_op, 1), 1))
-                   || (GET_CODE (temp) == REG
-                       && REGNO (temp) < FIRST_PSEUDO_REGISTER))
-                 temp = gen_reg_rtx (mode);
-               store_expr (singleton, temp,
-                           modifier == EXPAND_STACK_PARM ? 2 : 0);
-             }
-           else
-             expand_expr (singleton,
-                          ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
-           if (singleton == TREE_OPERAND (exp, 1))
-             jumpif (TREE_OPERAND (exp, 0), op0);
-           else
-             jumpifnot (TREE_OPERAND (exp, 0), op0);
-
-           start_cleanup_deferral ();
-           if (binary_op && temp == 0)
-             /* Just touch the other operand.  */
-             expand_expr (TREE_OPERAND (binary_op, 1),
-                          ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
-           else if (binary_op)
-             store_expr (build (TREE_CODE (binary_op), type,
-                                make_tree (type, temp),
-                                TREE_OPERAND (binary_op, 1)),
-                         temp, modifier == EXPAND_STACK_PARM ? 2 : 0);
-           else
-             store_expr (build1 (TREE_CODE (unary_op), type,
-                                 make_tree (type, temp)),
-                         temp, modifier == EXPAND_STACK_PARM ? 2 : 0);
-           op1 = op0;
-         }
-       /* Check for A op 0 ? A : FOO and A op 0 ? FOO : A where OP is any
-          comparison operator.  If we have one of these cases, set the
-          output to A, branch on A (cse will merge these two references),
-          then set the output to FOO.  */
-       else if (temp
-                && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<'
-                && integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 1))
-                && operand_equal_p (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
-                                    TREE_OPERAND (exp, 1), 0)
-                && (! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
-                    || TREE_CODE (TREE_OPERAND (exp, 1)) == SAVE_EXPR)
-                && safe_from_p (temp, TREE_OPERAND (exp, 2), 1))
-         {
-           if (GET_CODE (temp) == REG
-               && REGNO (temp) < FIRST_PSEUDO_REGISTER)
-             temp = gen_reg_rtx (mode);
-           store_expr (TREE_OPERAND (exp, 1), temp,
-                       modifier == EXPAND_STACK_PARM ? 2 : 0);
-           jumpif (TREE_OPERAND (exp, 0), op0);
-
-           start_cleanup_deferral ();
-           store_expr (TREE_OPERAND (exp, 2), temp,
-                       modifier == EXPAND_STACK_PARM ? 2 : 0);
-           op1 = op0;
-         }
-       else if (temp
-                && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<'
-                && integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 1))
-                && operand_equal_p (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
-                                    TREE_OPERAND (exp, 2), 0)
-                && (! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
-                    || TREE_CODE (TREE_OPERAND (exp, 2)) == SAVE_EXPR)
-                && safe_from_p (temp, TREE_OPERAND (exp, 1), 1))
-         {
-           if (GET_CODE (temp) == REG
-               && REGNO (temp) < FIRST_PSEUDO_REGISTER)
-             temp = gen_reg_rtx (mode);
-           store_expr (TREE_OPERAND (exp, 2), temp,
-                       modifier == EXPAND_STACK_PARM ? 2 : 0);
-           jumpifnot (TREE_OPERAND (exp, 0), op0);
-
-           start_cleanup_deferral ();
-           store_expr (TREE_OPERAND (exp, 1), temp,
-                       modifier == EXPAND_STACK_PARM ? 2 : 0);
-           op1 = op0;
-         }
-       else
-         {
-           op1 = gen_label_rtx ();
-           jumpifnot (TREE_OPERAND (exp, 0), op0);
-
-           start_cleanup_deferral ();
-
-           /* One branch of the cond can be void, if it never returns. For
-              example A ? throw : E  */
-           if (temp != 0
-               && 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);
-           end_cleanup_deferral ();
-           emit_queue ();
-           emit_jump_insn (gen_jump (op1));
-           emit_barrier ();
-           emit_label (op0);
-           start_cleanup_deferral ();
-           if (temp != 0
-               && 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);
-         }
-
-       end_cleanup_deferral ();
-
-       emit_queue ();
-       emit_label (op1);
-       OK_DEFER_POP;
-
-       return temp;
-      }
+               emit_move_insn (target, const0_rtx);
 
-    case TARGET_EXPR:
-      {
-       /* Something needs to be initialized, but we didn't know
-          where that thing was when building the tree.  For example,
-          it could be the return value of a function, or a parameter
-          to a function which lays down in the stack, or a temporary
-          variable which must be passed by reference.
+             return target;
+           }
 
-          We guarantee that the expression will either be constructed
-          or copied into our original target.  */
+         if (temp != original_target)
+           {
+             enum machine_mode mode1 = GET_MODE (temp);
+             if (mode1 == VOIDmode)
+               mode1 = tmode != VOIDmode ? tmode : mode;
 
-       tree slot = TREE_OPERAND (exp, 0);
-       tree cleanups = NULL_TREE;
-       tree exp1;
+             temp = copy_to_mode_reg (mode1, temp);
+           }
 
-       if (TREE_CODE (slot) != VAR_DECL)
-         abort ();
+         op1 = gen_label_rtx ();
+         emit_cmp_and_jump_insns (temp, const0_rtx, EQ, NULL_RTX,
+                                  GET_MODE (temp), unsignedp, op1);
+         emit_move_insn (temp, const1_rtx);
+         emit_label (op1);
+         return temp;
+       }
 
-       if (! ignore)
-         target = original_target;
+      /* If no set-flag instruction, must generate a conditional store
+        into a temporary variable.  Drop through and handle this
+        like && and ||.  */
 
-       /* Set this here so that if we get a target that refers to a
-          register variable that's already been used, put_reg_into_stack
-          knows that it should fix up those uses.  */
-       TREE_USED (slot) = 1;
+      if (! ignore
+         && (target == 0
+             || modifier == EXPAND_STACK_PARM
+             || ! 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 && REG_P (target)
+                 && REGNO (target) < FIRST_PSEUDO_REGISTER)))
+       target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
 
-       if (target == 0)
-         {
-           if (DECL_RTL_SET_P (slot))
-             {
-               target = DECL_RTL (slot);
-               /* If we have already expanded the slot, so don't do
-                  it again.  (mrs)  */
-               if (TREE_OPERAND (exp, 1) == NULL_TREE)
-                 return target;
-             }
-           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);
-
-               /* Since SLOT is not known to the called function
-                  to belong to its stack frame, we must build an explicit
-                  cleanup.  This case occurs when we must build up a reference
-                  to pass the reference as an argument.  In this case,
-                  it is very likely that such a reference need not be
-                  built here.  */
-
-               if (TREE_OPERAND (exp, 2) == 0)
-                 TREE_OPERAND (exp, 2)
-                   = (*lang_hooks.maybe_build_cleanup) (slot);
-               cleanups = TREE_OPERAND (exp, 2);
-             }
-         }
-       else
-         {
-           /* This case does occur, when expanding a parameter which
-              needs to be constructed on the stack.  The target
-              is the actual stack address that we want to initialize.
-              The function we call will perform the cleanup in this case.  */
-
-           /* If we have already assigned it space, use that space,
-              not target that we were passed in, as our target
-              parameter is only a hint.  */
-           if (DECL_RTL_SET_P (slot))
-             {
-               target = DECL_RTL (slot);
-               /* If we have already expanded the slot, so don't do
-                   it again.  (mrs)  */
-               if (TREE_OPERAND (exp, 1) == NULL_TREE)
-                 return target;
-             }
-           else
-             {
-               SET_DECL_RTL (slot, target);
-               /* If we must have an addressable slot, then make sure that
-                  the RTL that we just stored in slot is OK.  */
-               if (TREE_ADDRESSABLE (slot))
-                 put_var_into_stack (slot, /*rescan=*/true);
-             }
-         }
+      if (target)
+       emit_move_insn (target, const0_rtx);
 
-       exp1 = TREE_OPERAND (exp, 3) = TREE_OPERAND (exp, 1);
-       /* Mark it as expanded.  */
-       TREE_OPERAND (exp, 1) = NULL_TREE;
+      op1 = gen_label_rtx ();
+      jumpifnot (exp, op1);
 
-       store_expr (exp1, target, modifier == EXPAND_STACK_PARM ? 2 : 0);
+      if (target)
+       emit_move_insn (target, const1_rtx);
 
-       expand_decl_cleanup_eh (NULL_TREE, cleanups, CLEANUP_EH_ONLY (exp));
+      emit_label (op1);
+      return ignore ? const0_rtx : target;
 
-       return target;
-      }
+    case TRUTH_NOT_EXPR:
+      if (modifier == EXPAND_STACK_PARM)
+       target = 0;
+      op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
+      /* The parser is careful to generate TRUTH_NOT_EXPR
+        only with operands that are always zero or one.  */
+      temp = expand_binop (mode, xor_optab, op0, const1_rtx,
+                          target, 1, OPTAB_LIB_WIDEN);
+      gcc_assert (temp);
+      return temp;
 
-    case INIT_EXPR:
+    case STATEMENT_LIST:
       {
-       tree lhs = TREE_OPERAND (exp, 0);
-       tree rhs = TREE_OPERAND (exp, 1);
+       tree_stmt_iterator iter;
 
-       temp = expand_assignment (lhs, rhs, ! ignore);
-       return temp;
+       gcc_assert (ignore);
+
+       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);
+
+         gcc_assert (TREE_CODE (then_) == GOTO_EXPR
+                     && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL
+                     && TREE_CODE (else_) == GOTO_EXPR
+                     && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL);
+
+         jumpif (pred, label_rtx (GOTO_DESTINATION (then_)));
+         return expand_expr (else_, const0_rtx, VOIDmode, 0);
+       }
+
+        /* Note that COND_EXPRs whose type is a structure or union
+        are required to be constructed to contain assignments of
+        a temporary variable, so that we can evaluate them here
+        for side effect only.  If type is void, we must do likewise.  */
+
+        gcc_assert (!TREE_ADDRESSABLE (type)
+                   && !ignore
+                   && TREE_TYPE (TREE_OPERAND (exp, 1)) != void_type_node
+                   && TREE_TYPE (TREE_OPERAND (exp, 2)) != void_type_node);
+
+       /* If we are not to produce a result, we have no target.  Otherwise,
+        if a target was specified use it; it will not be used as an
+        intermediate target unless it is safe.  If no target, use a
+        temporary.  */
+
+       if (modifier != EXPAND_STACK_PARM
+         && original_target
+         && safe_from_p (original_target, TREE_OPERAND (exp, 0), 1)
+         && GET_MODE (original_target) == mode
+#ifdef HAVE_conditional_move
+         && (! can_conditionally_move_p (mode)
+             || REG_P (original_target))
+#endif
+         && !MEM_P (original_target))
+       temp = original_target;
+       else
+       temp = assign_temp (type, 0, 0, 1);
+
+       do_pending_stack_adjust ();
+       NO_DEFER_POP;
+       op0 = gen_label_rtx ();
+       op1 = gen_label_rtx ();
+       jumpifnot (TREE_OPERAND (exp, 0), op0);
+       store_expr (TREE_OPERAND (exp, 1), temp,
+                 modifier == EXPAND_STACK_PARM ? 2 : 0);
+
+       emit_jump_insn (gen_jump (op1));
+       emit_barrier ();
+       emit_label (op0);
+       store_expr (TREE_OPERAND (exp, 2), temp,
+                 modifier == EXPAND_STACK_PARM ? 2 : 0);
+
+       emit_label (op1);
+       OK_DEFER_POP;
+       return temp;
 
     case MODIFY_EXPR:
       {
@@ -9209,178 +8063,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        expand_return (TREE_OPERAND (exp, 0));
       return const0_rtx;
 
-    case PREINCREMENT_EXPR:
-    case PREDECREMENT_EXPR:
-      return expand_increment (exp, 0, ignore);
-
-    case POSTINCREMENT_EXPR:
-    case POSTDECREMENT_EXPR:
-      /* Faster to treat as pre-increment if result is not used.  */
-      return expand_increment (exp, ! ignore, ignore);
-
     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)
-       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
-        call force_const_mem at top level.  */
-      else if (cfun == 0
-              && (TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR
-                  || (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0)))
-                      == 'c')))
-       op0 = XEXP (output_constant_def (TREE_OPERAND (exp, 0), 0), 0);
-      else
-       {
-         /* We make sure to pass const0_rtx down if we came in with
-            ignore set, to avoid doing the cleanups twice for something.  */
-         op0 = expand_expr (TREE_OPERAND (exp, 0),
-                            ignore ? const0_rtx : NULL_RTX, VOIDmode,
-                            (modifier == EXPAND_INITIALIZER
-                             ? modifier : EXPAND_CONST_ADDRESS));
-
-         /* If we are going to ignore the result, OP0 will have been set
-            to const0_rtx, so just return it.  Don't get confused and
-            think we are taking the address of the constant.  */
-         if (ignore)
-           return op0;
-
-         /* Pass 1 for MODIFY, so that protect_from_queue doesn't get
-            clever and returns a REG when given a MEM.  */
-         op0 = protect_from_queue (op0, 1);
-
-         /* We would like the object in memory.  If it is a constant, we can
-            have it be statically allocated into memory.  For a non-constant,
-            we need to allocate some memory and store the value into it.  */
-
-         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
-                  || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF
-                  || GET_CODE (op0) == PARALLEL || GET_CODE (op0) == LO_SUM)
-           {
-             /* If the operand is a SAVE_EXPR, we can deal with this by
-                forcing the SAVE_EXPR into memory.  */
-             if (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR)
-               {
-                 put_var_into_stack (TREE_OPERAND (exp, 0),
-                                     /*rescan=*/true);
-                 op0 = SAVE_EXPR_RTL (TREE_OPERAND (exp, 0));
-               }
-             else
-               {
-                 /* If this object is in a register, it can't be BLKmode.  */
-                 tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
-                 rtx memloc = assign_temp (inner_type, 1, 1, 1);
-
-                 if (GET_CODE (op0) == PARALLEL)
-                   /* Handle calls that pass values in multiple
-                      non-contiguous locations.  The Irix 6 ABI has examples
-                      of this.  */
-                   emit_group_store (memloc, op0, inner_type,
-                                     int_size_in_bytes (inner_type));
-                 else
-                   emit_move_insn (memloc, op0);
-
-                 op0 = memloc;
-               }
-           }
-
-         if (GET_CODE (op0) != MEM)
-           abort ();
-
-         mark_temp_addr_taken (op0);
-         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)
-               op0 = convert_memory_address (ptr_mode, op0);
-#endif
-             return op0;
-           }
-
-         /* If OP0 is not aligned as least as much as the type requires, we
-            need to make a temporary, copy OP0 to it, and take the address of
-            the temporary.  We want to use the alignment of the type, not of
-            the operand.  Note that this is incorrect for FUNCTION_TYPE, but
-            the test for BLKmode means that can't happen.  The test for
-            BLKmode is because we never make mis-aligned MEMs with
-            non-BLKmode.
-
-            We don't need to do this at all if the machine doesn't have
-            strict alignment.  */
-         if (STRICT_ALIGNMENT && GET_MODE (op0) == BLKmode
-             && (TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0)))
-                 > MEM_ALIGN (op0))
-             && MEM_ALIGN (op0) < BIGGEST_ALIGNMENT)
-           {
-             tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
-             rtx new;
-
-             if (TYPE_ALIGN_OK (inner_type))
-               abort ();
-
-             if (TREE_ADDRESSABLE (inner_type))
-               {
-                 /* We can't make a bitwise copy of this object, so fail.  */
-                 error ("cannot take the address of an unaligned member");
-                 return const0_rtx;
-               }
-
-             new = assign_stack_temp_for_type
-               (TYPE_MODE (inner_type),
-                MEM_SIZE (op0) ? INTVAL (MEM_SIZE (op0))
-                : int_size_in_bytes (inner_type),
-                1, build_qualified_type (inner_type,
-                                         (TYPE_QUALS (inner_type)
-                                          | TYPE_QUAL_CONST)));
-
-             emit_block_move (new, op0, expr_size (TREE_OPERAND (exp, 0)),
-                              (modifier == EXPAND_STACK_PARM
-                               ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
-
-             op0 = new;
-           }
-
-         op0 = force_operand (XEXP (op0, 0), target);
-       }
-
-      if (flag_force_addr
-         && GET_CODE (op0) != REG
-         && modifier != EXPAND_CONST_ADDRESS
-         && modifier != EXPAND_INITIALIZER
-         && modifier != EXPAND_SUM)
-       op0 = force_reg (Pmode, op0);
-
-      if (GET_CODE (op0) == REG
-         && ! 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)
-       op0 = convert_memory_address (ptr_mode, op0);
-#endif
-
-      return op0;
-
-    case ENTRY_VALUE_EXPR:
-      abort ();
+      return expand_expr_addr_expr (TREE_OPERAND (exp, 0), target,
+                                   tmode, modifier);
 
     /* COMPLEX type for Extended Pascal & Fortran  */
     case COMPLEX_EXPR:
@@ -9424,158 +8109,117 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
       return gen_imagpart (mode, op0);
 
-    case CONJ_EXPR:
-      {
-       enum machine_mode partmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
-       rtx imag_t;
-       rtx insns;
-
-       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
-
-       if (! target)
-         target = gen_reg_rtx (mode);
-
-       start_sequence ();
-
-       /* Store the realpart and the negated imagpart to target.  */
-       emit_move_insn (gen_realpart (partmode, target),
-                       gen_realpart (partmode, op0));
-
-       imag_t = gen_imagpart (partmode, target);
-       temp = expand_unop (partmode,
-                           ! unsignedp && flag_trapv
-                           && (GET_MODE_CLASS(partmode) == MODE_INT)
-                           ? negv_optab : neg_optab,
-                           gen_imagpart (partmode, op0), imag_t, 0);
-       if (temp != imag_t)
-         emit_move_insn (imag_t, temp);
-
-       insns = get_insns ();
-       end_sequence ();
-
-       /* Conjugate should appear as a single unit
-          If TARGET is a CONCAT, we got insns like RD = RS, ID = - IS,
-          each with a separate pseudo as destination.
-          It's not correct for flow to treat them as a unit.  */
-       if (GET_CODE (target) != CONCAT)
-         emit_no_conflict_block (insns, target, op0, NULL_RTX, NULL_RTX);
-       else
-         emit_insn (insns);
-
-       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);
-
-       return op0;
-      }
-
+    case CATCH_EXPR:
+    case EH_FILTER_EXPR:
     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)
-         {
-           /* In this case, wrapping FINALLY_BLOCK in an UNSAVE_EXPR
-              is not sufficient, so we cannot expand the block twice.
-              So we play games with GOTO_SUBROUTINE_EXPR to let us
-              expand the thing only once.  */
-           /* When not optimizing, we go ahead with this form since
-              (1) user breakpoints operate more predictably without
-                  code duplication, and
-              (2) we're not running any of the global optimizers
-                  that would explode in time/space with the highly
-                  connected CFG created by the indirect branching.  */
-
-           rtx finally_label = gen_label_rtx ();
-           rtx done_label = gen_label_rtx ();
-           rtx return_link = gen_reg_rtx (Pmode);
-           tree cleanup = build (GOTO_SUBROUTINE_EXPR, void_type_node,
-                                 (tree) finally_label, (tree) return_link);
-           TREE_SIDE_EFFECTS (cleanup) = 1;
-
-           /* Start a new binding layer that will keep track of all cleanup
-              actions to be performed.  */
-           expand_start_bindings (2);
-           target_temp_slot_level = temp_slot_level;
-
-           expand_decl_cleanup (NULL_TREE, cleanup);
-           op0 = expand_expr (try_block, target, tmode, modifier);
-
-           preserve_temp_slots (op0);
-           expand_end_bindings (NULL_TREE, 0, 0);
-           emit_jump (done_label);
-           emit_label (finally_label);
-           expand_expr (finally_block, const0_rtx, VOIDmode, 0);
-           emit_indirect_jump (return_link);
-           emit_label (done_label);
-         }
-       else
-         {
-           expand_start_bindings (2);
-           target_temp_slot_level = temp_slot_level;
-
-           expand_decl_cleanup (NULL_TREE, finally_block);
-           op0 = expand_expr (try_block, target, tmode, modifier);
-
-           preserve_temp_slots (op0);
-           expand_end_bindings (NULL_TREE, 0, 0);
-         }
-
-       return op0;
-      }
-
-    case GOTO_SUBROUTINE_EXPR:
-      {
-       rtx subr = (rtx) TREE_OPERAND (exp, 0);
-       rtx return_link = *(rtx *) &TREE_OPERAND (exp, 1);
-       rtx return_address = gen_label_rtx ();
-       emit_move_insn (return_link,
-                       gen_rtx_LABEL_REF (Pmode, return_address));
-       emit_jump (subr);
-       emit_label (return_address);
-       return const0_rtx;
-      }
+      /* Lowered by tree-eh.c.  */
+      gcc_unreachable ();
 
+    case WITH_CLEANUP_EXPR:
+    case CLEANUP_POINT_EXPR:
+    case TARGET_EXPR:
+    case CASE_LABEL_EXPR:
     case VA_ARG_EXPR:
-      return expand_builtin_va_arg (TREE_OPERAND (exp, 0), type);
+    case BIND_EXPR:
+    case INIT_EXPR:
+    case CONJ_EXPR:
+    case COMPOUND_EXPR:
+    case PREINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case LOOP_EXPR:
+    case EXIT_EXPR:
+    case LABELED_BLOCK_EXPR:
+    case EXIT_BLOCK_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+      /* Lowered by gimplify.c.  */
+      gcc_unreachable ();
 
     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 ();
+      gcc_unreachable ();
+
+    case SWITCH_EXPR:
+      expand_case (exp);
+      return const0_rtx;
+
+    case LABEL_EXPR:
+      expand_label (TREE_OPERAND (exp, 0));
+      return const0_rtx;
+
+    case ASM_EXPR:
+      expand_asm_expr (exp);
+      return const0_rtx;
+
+    case WITH_SIZE_EXPR:
+      /* WITH_SIZE_EXPR expands to its first argument.  The caller should
+        have pulled out the size to use in whatever context it needed.  */
+      return expand_expr_real (TREE_OPERAND (exp, 0), original_target, tmode,
+                              modifier, alt_rtl);
 
     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'.  */
+  /* Here to do an ordinary binary operator.  */
  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:
+  this_optab = optab_for_tree_code (code, type);
+ binop3:
   if (modifier == EXPAND_STACK_PARM)
     target = 0;
   temp = expand_binop (mode, this_optab, op0, op1, target,
                       unsignedp, OPTAB_LIB_WIDEN);
-  if (temp == 0)
-    abort ();
-  return temp;
+  gcc_assert (temp);
+  return REDUCE_BIT_FIELD (temp);
+}
+#undef REDUCE_BIT_FIELD
+\f
+/* Subroutine of above: reduce EXP to the precision of TYPE (in the
+   signedness of TYPE), possibly returning the result in TARGET.  */
+static rtx
+reduce_to_bit_field_precision (rtx exp, rtx target, tree type)
+{
+  HOST_WIDE_INT prec = TYPE_PRECISION (type);
+  if (target && GET_MODE (target) != GET_MODE (exp))
+    target = 0;
+  if (TYPE_UNSIGNED (type))
+    {
+      rtx mask;
+      if (prec < HOST_BITS_PER_WIDE_INT)
+       mask = immed_double_const (((unsigned HOST_WIDE_INT) 1 << prec) - 1, 0,
+                                  GET_MODE (exp));
+      else
+       mask = immed_double_const ((unsigned HOST_WIDE_INT) -1,
+                                  ((unsigned HOST_WIDE_INT) 1
+                                   << (prec - HOST_BITS_PER_WIDE_INT)) - 1,
+                                  GET_MODE (exp));
+      return expand_and (GET_MODE (exp), exp, mask, target);
+    }
+  else
+    {
+      tree count = build_int_cst (NULL_TREE,
+                                 GET_MODE_BITSIZE (GET_MODE (exp)) - prec);
+      exp = expand_shift (LSHIFT_EXPR, GET_MODE (exp), exp, count, target, 0);
+      return expand_shift (RSHIFT_EXPR, GET_MODE (exp), exp, count, target, 0);
+    }
 }
 \f
 /* Subroutine of above: returns 1 if OFFSET corresponds to an offset that
@@ -9585,18 +8229,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;
 
@@ -9617,13 +8261,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
@@ -9642,6 +8281,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);
@@ -9667,209 +8313,6 @@ string_constant (tree arg, tree *ptr_offset)
   return 0;
 }
 \f
-/* Expand code for a post- or pre- increment or decrement
-   and return the RTX for the result.
-   POST is 1 for postinc/decrements and 0 for preinc/decrements.  */
-
-static rtx
-expand_increment (tree exp, int post, int ignore)
-{
-  rtx op0, op1;
-  rtx temp, value;
-  tree incremented = TREE_OPERAND (exp, 0);
-  optab this_optab = add_optab;
-  int icode;
-  enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
-  int op0_is_copy = 0;
-  int single_insn = 0;
-  /* 1 means we can't store into OP0 directly,
-     because it is a subreg narrower than a word,
-     and we don't dare clobber the rest of the word.  */
-  int bad_subreg = 0;
-
-  /* Stabilize any component ref that might need to be
-     evaluated more than once below.  */
-  if (!post
-      || TREE_CODE (incremented) == BIT_FIELD_REF
-      || (TREE_CODE (incremented) == COMPONENT_REF
-         && (TREE_CODE (TREE_OPERAND (incremented, 0)) != INDIRECT_REF
-             || DECL_BIT_FIELD (TREE_OPERAND (incremented, 1)))))
-    incremented = stabilize_reference (incremented);
-  /* Nested *INCREMENT_EXPRs can happen in C++.  We must force innermost
-     ones into save exprs so that they don't accidentally get evaluated
-     more than once by the code below.  */
-  if (TREE_CODE (incremented) == PREINCREMENT_EXPR
-      || TREE_CODE (incremented) == PREDECREMENT_EXPR)
-    incremented = save_expr (incremented);
-
-  /* Compute the operands as RTX.
-     Note whether OP0 is the actual lvalue or a copy of it:
-     I believe it is a copy iff it is a register or subreg
-     and insns were generated in computing it.  */
-
-  temp = get_last_insn ();
-  op0 = expand_expr (incremented, NULL_RTX, VOIDmode, 0);
-
-  /* If OP0 is a SUBREG made for a promoted variable, we cannot increment
-     in place but instead must do sign- or zero-extension during assignment,
-     so we copy it into a new register and let the code below use it as
-     a copy.
-
-     Note that we can safely modify this SUBREG since it is know not to be
-     shared (it was made by the expand_expr call above).  */
-
-  if (GET_CODE (op0) == SUBREG && SUBREG_PROMOTED_VAR_P (op0))
-    {
-      if (post)
-       SUBREG_REG (op0) = copy_to_reg (SUBREG_REG (op0));
-      else
-       bad_subreg = 1;
-    }
-  else if (GET_CODE (op0) == SUBREG
-          && GET_MODE_BITSIZE (GET_MODE (op0)) < BITS_PER_WORD)
-    {
-      /* We cannot increment this SUBREG in place.  If we are
-        post-incrementing, get a copy of the old value.  Otherwise,
-        just mark that we cannot increment in place.  */
-      if (post)
-       op0 = copy_to_reg (op0);
-      else
-       bad_subreg = 1;
-    }
-
-  op0_is_copy = ((GET_CODE (op0) == SUBREG || GET_CODE (op0) == REG)
-                && temp != get_last_insn ());
-  op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
-
-  /* Decide whether incrementing or decrementing.  */
-  if (TREE_CODE (exp) == POSTDECREMENT_EXPR
-      || TREE_CODE (exp) == PREDECREMENT_EXPR)
-    this_optab = sub_optab;
-
-  /* Convert decrement by a constant into a negative increment.  */
-  if (this_optab == sub_optab
-      && GET_CODE (op1) == CONST_INT)
-    {
-      op1 = GEN_INT (-INTVAL (op1));
-      this_optab = add_optab;
-    }
-
-  if (TYPE_TRAP_SIGNED (TREE_TYPE (exp)))
-    this_optab = this_optab == add_optab ? addv_optab : subv_optab;
-
-  /* For a preincrement, see if we can do this with a single instruction.  */
-  if (!post)
-    {
-      icode = (int) this_optab->handlers[(int) mode].insn_code;
-      if (icode != (int) CODE_FOR_nothing
-         /* Make sure that OP0 is valid for operands 0 and 1
-            of the insn we want to queue.  */
-         && (*insn_data[icode].operand[0].predicate) (op0, mode)
-         && (*insn_data[icode].operand[1].predicate) (op0, mode)
-         && (*insn_data[icode].operand[2].predicate) (op1, mode))
-       single_insn = 1;
-    }
-
-  /* If OP0 is not the actual lvalue, but rather a copy in a register,
-     then we cannot just increment OP0.  We must therefore contrive to
-     increment the original value.  Then, for postincrement, we can return
-     OP0 since it is a copy of the old value.  For preincrement, expand here
-     unless we can do it with a single insn.
-
-     Likewise if storing directly into OP0 would clobber high bits
-     we need to preserve (bad_subreg).  */
-  if (op0_is_copy || (!post && !single_insn) || bad_subreg)
-    {
-      /* This is the easiest way to increment the value wherever it is.
-        Problems with multiple evaluation of INCREMENTED are prevented
-        because either (1) it is a component_ref or preincrement,
-        in which case it was stabilized above, or (2) it is an array_ref
-        with constant index in an array in a register, which is
-        safe to reevaluate.  */
-      tree newexp = build (((TREE_CODE (exp) == POSTDECREMENT_EXPR
-                            || TREE_CODE (exp) == PREDECREMENT_EXPR)
-                           ? MINUS_EXPR : PLUS_EXPR),
-                          TREE_TYPE (exp),
-                          incremented,
-                          TREE_OPERAND (exp, 1));
-
-      while (TREE_CODE (incremented) == NOP_EXPR
-            || TREE_CODE (incremented) == CONVERT_EXPR)
-       {
-         newexp = convert (TREE_TYPE (incremented), newexp);
-         incremented = TREE_OPERAND (incremented, 0);
-       }
-
-      temp = expand_assignment (incremented, newexp, ! post && ! ignore);
-      return post ? op0 : temp;
-    }
-
-  if (post)
-    {
-      /* 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
-        that often results if we must increment now and first save
-        the old value for subsequent use.  */
-
-#if 0  /* Turned off to avoid making extra insn for indexed memref.  */
-      op0 = stabilize (op0);
-#endif
-
-      icode = (int) this_optab->handlers[(int) mode].insn_code;
-      if (icode != (int) CODE_FOR_nothing
-         /* Make sure that OP0 is valid for operands 0 and 1
-            of the insn we want to queue.  */
-         && (*insn_data[icode].operand[0].predicate) (op0, mode)
-         && (*insn_data[icode].operand[1].predicate) (op0, mode))
-       {
-         if (! (*insn_data[icode].operand[2].predicate) (op1, mode))
-           op1 = force_reg (mode, op1);
-
-         return enqueue_insn (op0, GEN_FCN (icode) (op0, op0, op1));
-       }
-      if (icode != (int) CODE_FOR_nothing && GET_CODE (op0) == MEM)
-       {
-         rtx addr = (general_operand (XEXP (op0, 0), mode)
-                     ? force_reg (Pmode, XEXP (op0, 0))
-                     : copy_to_reg (XEXP (op0, 0)));
-         rtx temp, result;
-
-         op0 = replace_equiv_address (op0, addr);
-         temp = force_reg (GET_MODE (op0), op0);
-         if (! (*insn_data[icode].operand[2].predicate) (op1, mode))
-           op1 = force_reg (mode, op1);
-
-         /* The increment queue is LIFO, thus we have to `queue'
-            the instructions in reverse order.  */
-         enqueue_insn (op0, gen_move_insn (op0, temp));
-         result = enqueue_insn (temp, GEN_FCN (icode) (temp, temp, op1));
-         return result;
-       }
-    }
-
-  /* Preincrement, or we can't increment with one simple insn.  */
-  if (post)
-    /* Save a copy of the value before inc or dec, to return it later.  */
-    temp = value = copy_to_reg (op0);
-  else
-    /* Arrange to return the incremented value.  */
-    /* Copy the rtx because expand_binop will protect from the queue,
-       and the results of that would be invalid for us to return
-       if our caller does emit_queue before using our result.  */
-    temp = copy_rtx (value = op0);
-
-  /* Increment however we can.  */
-  op1 = expand_binop (mode, this_optab, value, op1, op0,
-                     TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
-
-  /* Make sure the value is stored into OP0.  */
-  if (op1 != op0)
-    emit_move_insn (op0, op1);
-
-  return temp;
-}
-\f
 /* Generate code to calculate EXP using a store-flag instruction
    and return an rtx for the result.  EXP is either a comparison
    or a TRUTH_NOT_EXPR whose operand is a comparison.
@@ -9921,7 +8364,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.  */
@@ -10005,9 +8448,12 @@ 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 ();
+      gcc_unreachable ();
     }
 
   /* Put a constant second.  */
@@ -10030,9 +8476,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);
     }
 
@@ -10062,23 +8508,15 @@ 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);
 
-  /* Pass copies of OP0 and OP1 in case they contain a QUEUED.  This is safe
-     because, if the emit_store_flag does anything it will succeed and
-     OP0 and OP1 will not be used subsequently.  */
-
-  result = emit_store_flag (target, code,
-                           queued_subexp_p (op0) ? copy_rtx (op0) : op0,
-                           queued_subexp_p (op1) ? copy_rtx (op1) : op1,
+  result = emit_store_flag (target, code, op0, op1,
                            operand_mode, unsignedp, 1);
 
   if (result)
@@ -10090,7 +8528,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));
 
@@ -10111,8 +8549,7 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
   code = GET_CODE (result);
 
   label = gen_label_rtx ();
-  if (bcc_gen_fctn[(int) code] == 0)
-    abort ();
+  gcc_assert (bcc_gen_fctn[(int) code]);
 
   emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label));
   emit_move_insn (target, invert ? const1_rtx : const0_rtx);
@@ -10163,8 +8600,8 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
       rtx rangertx = expand_expr (range, NULL_RTX, VOIDmode, 0);
 
       /* We must handle the endpoints in the original mode.  */
-      index_expr = build (MINUS_EXPR, index_type,
-                         index_expr, minval);
+      index_expr = build2 (MINUS_EXPR, index_type,
+                          index_expr, minval);
       minval = integer_zero_node;
       index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
       emit_cmp_and_jump_insns (rangertx, index, LTU, NULL_RTX,
@@ -10176,15 +8613,14 @@ 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);
        }
 
       index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
     }
-  emit_queue ();
-  index = protect_from_queue (index, 0);
+
   do_pending_stack_adjust ();
 
   op_mode = insn_data[(int) CODE_FOR_casesi].operand[0].mode;
@@ -10196,7 +8632,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);
@@ -10205,7 +8641,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);
@@ -10257,11 +8693,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
 
@@ -10284,9 +8720,7 @@ do_tablejump (rtx index, enum machine_mode mode, rtx range, rtx table_label,
 #endif
     index = memory_address_noforce (CASE_VECTOR_MODE, index);
   temp = gen_reg_rtx (CASE_VECTOR_MODE);
-  vector = gen_rtx_MEM (CASE_VECTOR_MODE, index);
-  RTX_UNCHANGING_P (vector) = 1;
-  MEM_NOTRAP_P (vector) = 1;
+  vector = gen_const_mem (CASE_VECTOR_MODE, index);
   convert_move (temp, vector, 0);
 
   emit_jump_insn (gen_tablejump (temp, table_label));
@@ -10306,12 +8740,10 @@ try_tablejump (tree index_type, tree index_expr, tree minval, tree range,
   if (! HAVE_tablejump)
     return 0;
 
-  index_expr = fold (build (MINUS_EXPR, index_type,
-                           convert (index_type, index_expr),
-                           convert (index_type, minval)));
+  index_expr = fold (build2 (MINUS_EXPR, index_type,
+                            convert (index_type, index_expr),
+                            convert (index_type, minval)));
   index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
-  emit_queue ();
-  index = protect_from_queue (index, 0);
   do_pending_stack_adjust ();
 
   do_tablejump (index, TYPE_MODE (index_type),
@@ -10319,7 +8751,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;
 }
@@ -10340,7 +8772,7 @@ vector_mode_valid_p (enum machine_mode mode)
     return 0;
 
   /* Hardware support.  Woo hoo!  */
-  if (VECTOR_MODE_SUPPORTED_P (mode))
+  if (targetm.vector_mode_supported_p (mode))
     return 1;
 
   innermode = GET_MODE_INNER (mode);
@@ -10350,7 +8782,7 @@ vector_mode_valid_p (enum machine_mode mode)
 
   /* If we have support for the inner mode, we can safely emulate it.
      We may not have V2DI, but me can emulate with a pair of DIs.  */
-  return mov_optab->handlers[innermode].insn_code != CODE_FOR_nothing;
+  return targetm.scalar_mode_supported_p (innermode);
 }
 
 /* Return a CONST_VECTOR rtx for a VECTOR_CST tree.  */
@@ -10364,7 +8796,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);
@@ -10390,7 +8822,6 @@ const_vector_from_tree (tree exp)
   for (; i < units; ++i)
     RTVEC_ELT (v, i) = CONST0_RTX (inner);
 
-  return gen_rtx_raw_CONST_VECTOR (mode, v);
+  return gen_rtx_CONST_VECTOR (mode, v);
 }
-
 #include "gt-expr.h"