OSDN Git Service

(TARGET_CPU_CPP_BUILTINS): Add builtin assert of cpu=xstormy16.
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index a3f89a1..f949930 100644 (file)
@@ -77,14 +77,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #endif
 #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
@@ -127,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);
@@ -142,7 +134,7 @@ 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);
@@ -152,23 +144,21 @@ static void store_constructor_field (rtx, unsigned HOST_WIDE_INT,
                                     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);
+                       tree, tree, int);
 
 static unsigned HOST_WIDE_INT highest_pow2_factor (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);
 #endif
 static void do_tablejump (rtx, enum machine_mode, rtx, rtx, rtx);
 static rtx const_vector_from_tree (tree);
-static void execute_expand (void);
 
 /* Record for each mode whether we can move a register directly to or
    from an object of that mode in memory.  If we can't, we won't try
@@ -185,28 +175,32 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
    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)
+  (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.  */
@@ -320,215 +314,6 @@ init_expr (void)
 {
   cfun->expr = ggc_alloc_cleared (sizeof (struct expr_status));
 }
-
-/* 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;
-    }
-}
-
-/* Retrieve a mark on the queue.  */
-  
-static rtx
-mark_queue (void)
-{
-  return pending_chain;
-}
-
-/* Perform all the pending incrementations that have been enqueued
-   after MARK was retrieved.  If MARK is null, perform all the
-   pending incrementations.  */
-
-static void
-emit_insns_enqueued_after_mark (rtx mark)
-{
-  rtx p;
-
-  /* The marked incrementation may have been emitted in the meantime
-     through a call to emit_queue.  In this case, the mark is not valid
-     anymore so do nothing.  */
-  if (mark && ! QUEUED_BODY (mark))
-    return;
-
-  while ((p = pending_chain) != mark)
-    {
-      rtx body = QUEUED_BODY (p);
-
-      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;
-       }
-
-      QUEUED_BODY (p) = 0;
-      pending_chain = QUEUED_NEXT (p);
-    }
-}
-
-/* Perform all the pending incrementations.  */
-
-void
-emit_queue (void)
-{
-  emit_insns_enqueued_after_mark (NULL_RTX);
-}
 \f
 /* Copy data from FROM to TO, where the machine modes are not the same.
    Both modes may be integer, or both may be floating.
@@ -549,11 +334,8 @@ 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.  */
@@ -570,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)))
@@ -582,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);
@@ -606,12 +386,13 @@ convert_move (rtx to, rtx from, int unsignedp)
       rtx value, insns;
       convert_optab tab;
 
+      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 if (GET_MODE_PRECISION (from_mode) > GET_MODE_PRECISION (to_mode))
-       tab = trunc_optab;
       else
-       abort ();
+       tab = trunc_optab;
 
       /* Try converting directly if the insn is supported.  */
 
@@ -626,9 +407,8 @@ convert_move (rtx to, rtx from, int unsignedp)
       /* Otherwise use a libcall.  */
       libcall = tab->handlers[to_mode][from_mode].libfunc;
 
-      if (!libcall)
-       /* 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,
@@ -650,9 +430,8 @@ convert_move (rtx to, rtx from, int unsignedp)
       enum machine_mode full_mode
        = smallest_mode_for_size (GET_MODE_BITSIZE (to_mode), MODE_INT);
 
-      if (trunc_optab->handlers[to_mode][full_mode].insn_code
-         == CODE_FOR_nothing)
-       abort ();
+      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);
@@ -665,9 +444,8 @@ convert_move (rtx to, rtx from, int unsignedp)
       enum machine_mode full_mode
        = smallest_mode_for_size (GET_MODE_BITSIZE (from_mode), MODE_INT);
 
-      if (sext_optab->handlers[full_mode][from_mode].insn_code
-         == CODE_FOR_nothing)
-       abort ();
+      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);
@@ -774,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);
@@ -793,7 +570,7 @@ 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)))
@@ -812,7 +589,7 @@ convert_move (rtx to, rtx from, int unsignedp)
       && 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)))
@@ -863,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);
@@ -899,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
@@ -907,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)
@@ -926,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)
@@ -985,7 +757,7 @@ 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])
                      || (REG_P (x)
                          && (! HARD_REGISTER_P (x)
@@ -1019,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);
     }
 
@@ -1048,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.
@@ -1111,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);
@@ -1149,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.  */
@@ -1174,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)
@@ -1212,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);
@@ -1241,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;
 }
 
@@ -1291,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
        }
 
@@ -1345,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 ();
-
-  x = protect_from_queue (x, 1);
-  y = protect_from_queue (y, 0);
-  size = protect_from_queue (size, 0);
+  gcc_assert (MEM_P (x));
+  gcc_assert (MEM_P (y));
+  gcc_assert (size);
 
-  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.  */
@@ -1381,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);
@@ -1432,22 +1219,20 @@ block_move_libcall_safe_for_call_parm (void)
        rtx tmp = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
        if (!tmp || !REG_P (tmp))
          return false;
-#ifdef FUNCTION_ARG_PARTIAL_NREGS
        if (FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode,
                                        NULL_TREE, 1))
          return false;
-#endif
        FUNCTION_ARG_ADVANCE (args_so_far, mode, NULL_TREE, 1);
       }
   }
   return true;
 }
 
-/* A subroutine of emit_block_move.  Expand a movstr pattern;
+/* 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;
@@ -1463,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
@@ -1512,7 +1297,7 @@ emit_block_move_via_movstr (rtx x, rtx y, rtx size, unsigned int align)
   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
@@ -1523,26 +1308,9 @@ 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));
@@ -1553,10 +1321,7 @@ emit_block_move_via_libcall (rtx dst, rtx src, rtx size)
   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);
@@ -1565,46 +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 returning pointers, we could end up generating incorrect code.  */
 
-     For convenience, we generate the call to bcopy this way as well.  */
-
-  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);
+  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
@@ -1620,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;
@@ -1645,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
@@ -1662,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);
     }
 
@@ -1788,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));
     }
@@ -1807,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);
@@ -1830,19 +1557,36 @@ gen_group_rtx (rtx orig)
   return gen_rtx_PARALLEL (GET_MODE (orig), gen_rtvec_v (length, tmps));
 }
 
-/* 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.  */
+/* A subroutine of emit_group_load.  Arguments as for emit_group_load,
+   except that values are placed in TMPS[i], and must later be moved
+   into corresponding XEXP (XVECEXP (DST, 0, i), 0) element.  */
 
-void
-emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
+static void
+emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
 {
-  rtx *tmps, src;
+  rtx src;
   int start, i;
+  enum machine_mode m = GET_MODE (orig_src);
 
-  if (GET_CODE (dst) != PARALLEL)
-    abort ();
+  gcc_assert (GET_CODE (dst) == PARALLEL);
+
+  if (!SCALAR_INT_MODE_P (m)
+      && !MEM_P (orig_src) && GET_CODE (orig_src) != CONCAT)
+    {
+      enum machine_mode imode = int_mode_for_mode (GET_MODE (orig_src));
+      if (imode == BLKmode)
+       src = assign_stack_temp (GET_MODE (orig_src), ssize, 0);
+      else
+       src = gen_reg_rtx (imode);
+      if (imode != BLKmode)
+       src = gen_lowpart (GET_MODE (orig_src), src);
+      emit_move_insn (src, orig_src);
+      /* ...and back again.  */
+      if (imode != BLKmode)
+       src = gen_lowpart (imode, src);
+      emit_group_load_1 (tmps, dst, src, type, ssize);
+      return;
+    }
 
   /* Check for a NULL entry, used to indicate that the parameter goes
      both on the stack and in registers.  */
@@ -1851,8 +1595,6 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
   else
     start = 1;
 
-  tmps = alloca (sizeof (rtx) * XVECLEN (dst, 0));
-
   /* Process the pieces.  */
   for (i = start; i < XVECLEN (dst, 0); i++)
     {
@@ -1876,15 +1618,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)))
@@ -1898,7 +1639,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
@@ -1924,16 +1665,18 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
                  && (!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);
+             tmps[i] = extract_bit_field (mem, bytelen * BITS_PER_UNIT,
+                                          0, 1, NULL_RTX, mode, mode);
            }
-         else
-           abort ();
        }
       /* FIXME: A SIMD parallel will eventually lead to a subreg of a
         SIMD register, which is currently broken.  While we get GCC
@@ -1957,18 +1700,67 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
       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 code to move a block 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.  */
+
+void
+emit_group_load (rtx dst, rtx src, tree type, int ssize)
+{
+  rtx *tmps;
+  int i;
 
-  emit_queue ();
+  tmps = alloca (sizeof (rtx) * XVECLEN (dst, 0));
+  emit_group_load_1 (tmps, dst, src, type, ssize);
 
   /* 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]);
+  for (i = 0; i < XVECLEN (dst, 0); i++)
+    {
+      rtx d = XEXP (XVECEXP (dst, 0, i), 0);
+      if (d == NULL)
+       continue;
+      emit_move_insn (d, tmps[i]);
+    }
+}
+
+/* Similar, but load SRC into new pseudos in a format that looks like
+   PARALLEL.  This can later be fed to emit_group_move to get things
+   in the right place.  */
+
+rtx
+emit_group_load_into_temps (rtx parallel, rtx src, tree type, int ssize)
+{
+  rtvec vec;
+  int i;
+
+  vec = rtvec_alloc (XVECLEN (parallel, 0));
+  emit_group_load_1 (&RTVEC_ELT (vec, 0), parallel, src, type, ssize);
+
+  /* Convert the vector to look just like the original PARALLEL, except
+     with the computed values.  */
+  for (i = 0; i < XVECLEN (parallel, 0); i++)
+    {
+      rtx e = XVECEXP (parallel, 0, i);
+      rtx d = XEXP (e, 0);
+
+      if (d)
+       {
+         d = force_reg (GET_MODE (d), RTVEC_ELT (vec, i));
+         e = alloc_EXPR_LIST (REG_NOTE_KIND (e), d, XEXP (e, 1));
+       }
+      RTVEC_ELT (vec, i) = e;
+    }
+
+  return gen_rtx_PARALLEL (GET_MODE (parallel), vec);
 }
 
 /* Emit code to move a block SRC to block DST, where SRC and DST are
@@ -1979,10 +1771,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++)
@@ -1990,6 +1781,27 @@ emit_group_move (rtx dst, rtx src)
                    XEXP (XVECEXP (src, 0, i), 0));
 }
 
+/* Move a group of registers represented by a PARALLEL into pseudos.  */
+
+rtx
+emit_group_move_into_temps (rtx src)
+{
+  rtvec vec = rtvec_alloc (XVECLEN (src, 0));
+  int i;
+
+  for (i = 0; i < XVECLEN (src, 0); i++)
+    {
+      rtx e = XVECEXP (src, 0, i);
+      rtx d = XEXP (e, 0);
+
+      if (d)
+       e = alloc_EXPR_LIST (REG_NOTE_KIND (e), copy_to_reg (d), XEXP (e, 1));
+      RTVEC_ELT (vec, i) = e;
+    }
+
+  return gen_rtx_PARALLEL (GET_MODE (src), vec);
+}
+
 /* Emit code to move a block SRC to a block ORIG_DST of type TYPE,
    where SRC is non-consecutive registers represented by a PARALLEL.
    SSIZE represents the total size of block ORIG_DST, or -1 if not
@@ -2000,9 +1812,24 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
 {
   rtx *tmps, dst;
   int start, i;
+  enum machine_mode m = GET_MODE (orig_dst);
 
-  if (GET_CODE (src) != PARALLEL)
-    abort ();
+  gcc_assert (GET_CODE (src) == PARALLEL);
+
+  if (!SCALAR_INT_MODE_P (m)
+      && !MEM_P (orig_dst) && GET_CODE (orig_dst) != CONCAT)
+    {
+      enum machine_mode imode = int_mode_for_mode (GET_MODE (orig_dst));
+      if (imode == BLKmode)
+        dst = assign_stack_temp (GET_MODE (orig_dst), ssize, 0);
+      else
+        dst = gen_reg_rtx (imode);
+      emit_group_store (dst, src, type, ssize);
+      if (imode != BLKmode)
+        dst = gen_lowpart (GET_MODE (orig_dst), dst);
+      emit_move_insn (orig_dst, dst);
+      return;
+    }
 
   /* Check for a NULL entry, used to indicate that the parameter goes
      both on the stack and in registers.  */
@@ -2020,7 +1847,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.  */
@@ -2044,7 +1870,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.  */
@@ -2074,8 +1900,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;
        }
@@ -2089,8 +1916,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),
@@ -2098,12 +1926,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
@@ -2111,11 +1937,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);
@@ -2197,9 +2021,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;
@@ -2211,10 +2033,8 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
 void
 use_reg (rtx *call_fusage, rtx reg)
 {
-  if (!REG_P (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);
@@ -2228,8 +2048,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]);
@@ -2268,7 +2087,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;
@@ -2281,9 +2101,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.  */
@@ -2331,8 +2164,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;
@@ -2355,14 +2187,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;
@@ -2372,8 +2201,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)
@@ -2400,8 +2228,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)
@@ -2431,15 +2258,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;
 
@@ -2459,7 +2285,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);
@@ -2486,9 +2312,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.  */
@@ -2511,8 +2350,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
@@ -2561,7 +2399,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,
@@ -2572,15 +2410,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);
@@ -2589,11 +2424,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
@@ -2605,7 +2440,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
@@ -2645,7 +2480,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
@@ -2655,33 +2490,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);
 
@@ -2689,36 +2503,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);
+  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
@@ -2734,19 +2536,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;
@@ -2758,10 +2551,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
@@ -2775,7 +2565,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);
     }
 
@@ -2796,11 +2586,8 @@ 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));
 
   if (CONSTANT_P (y))
     {
@@ -2825,21 +2612,20 @@ 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);
 
@@ -2863,8 +2649,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
@@ -3044,8 +2829,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
@@ -3057,14 +2841,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);
@@ -3094,13 +2878,15 @@ emit_move_insn_1 (rtx x, rtx y)
   /* 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
@@ -3146,10 +2932,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);
 
@@ -3174,8 +2960,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);
 
@@ -3198,8 +2983,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
@@ -3262,7 +3045,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.
@@ -3463,7 +3245,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)
     {
@@ -3484,8 +3266,7 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
       else
        offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
 
-      if (size == 0)
-       abort ();
+      gcc_assert (size);
 
       used -= offset;
 
@@ -3580,16 +3361,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);
@@ -3685,15 +3461,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);
        }
@@ -3725,27 +3501,19 @@ 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.  */
           || !REG_P (x)
-          /* If the register is readonly, it can't be set more than once.  */
-          || RTX_UNCHANGING_P (x)
           /* Don't use hard regs to avoid extending their life.  */
           || 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.)
-   Otherwise, the returned value is NULL_RTX.  */
+/* Expand an assignment that stores the value of FROM into TO.  */
 
-rtx
-expand_assignment (tree to, tree from, int want_value)
+void
+expand_assignment (tree to, tree from)
 {
   rtx to_rtx = 0;
   rtx result;
@@ -3755,7 +3523,7 @@ expand_assignment (tree to, tree from, int want_value)
   if (TREE_CODE (to) == ERROR_MARK)
     {
       result = expand_expr (from, NULL_RTX, VOIDmode, 0);
-      return want_value ? result : NULL_RTX;
+      return;
     }
 
   /* Assignment of a structure component needs special treatment
@@ -3783,17 +3551,13 @@ expand_assignment (tree to, tree from, int want_value)
       /* If we are going to use store_bit_field and extract_bit_field,
         make sure to_rtx will be safe for multiple use.  */
 
-      if (mode1 == VOIDmode && want_value)
-       tem = stabilize_reference (tem);
-
       orig_to_rtx = to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0);
 
       if (offset != 0)
        {
          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)
@@ -3805,7 +3569,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
@@ -3822,7 +3586,7 @@ expand_assignment (tree to, tree from, int want_value)
                                                                   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.  */
@@ -3833,54 +3597,146 @@ 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))
-         /* We can't assert that a MEM won't be set more than once
-            if the component is not addressable because another
-            non-addressable component may be referenced by the same MEM.  */
-         && ! (GET_CODE (to_rtx) == MEM && ! can_address_p (to)))
+      if (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
+            && 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
+             || !BINARY_CLASS_P (src))
+           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 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,
-                                         TYPE_UNSIGNED (TREE_TYPE (to)))
-             : NULL_RTX);
-    }
+         if (! operand_equal_p (to, op0, 0))
+           break;
 
-  /* If the rhs is a function call and its value is not an aggregate,
+         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;
+
+           default:
+             break;
+           }
+
+         break;
+       }
+
+      result = store_field (to_rtx, bitsize, bitpos, mode1, from,
+                           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;
+    }
+
+  /* If the rhs is a function call and its value is not an aggregate,
      call the function before we start to compute the lhs.
      This is needed for correct code for cases such as
      val = setjmp (buf) on machines where reference to val
@@ -3918,7 +3774,7 @@ expand_assignment (tree to, tree from, int want_value)
       preserve_temp_slots (to_rtx);
       free_temp_slots ();
       pop_temp_slots ();
-      return want_value ? to_rtx : NULL_RTX;
+      return;
     }
 
   /* Ordinary treatment.  Expand TO to get a REG or MEM rtx.
@@ -3945,7 +3801,7 @@ expand_assignment (tree to, tree from, int want_value)
       preserve_temp_slots (to_rtx);
       free_temp_slots ();
       pop_temp_slots ();
-      return want_value ? to_rtx : NULL_RTX;
+      return;
     }
 
   /* In case we are returning the contents of an object which overlaps
@@ -3961,49 +3817,31 @@ 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, TYPE_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,
-                                           TYPE_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 ();
       pop_temp_slots ();
-      return want_value ? to_rtx : NULL_RTX;
+      return;
     }
 
   /* Compute FROM and store the value in the rtx we got.  */
 
   push_temp_slots ();
-  result = store_expr (from, to_rtx, want_value);
+  result = store_expr (from, to_rtx, 0);
   preserve_temp_slots (result);
   free_temp_slots ();
   pop_temp_slots ();
-  return want_value ? result : NULL_RTX;
+  return;
 }
 
 /* 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
-   value in a containing expression even if TARGET has something
-   else stored in it.  If possible, we copy the value through a pseudo
-   and return that pseudo.  Or, if the value is constant, we try to
-   return the constant.  In some cases, we return a pseudo
-   copied *from* TARGET.
 
    If the mode is BLKmode then we may return TARGET itself.
    It turns out that in BLKmode it doesn't cause a problem.
@@ -4012,29 +3850,22 @@ expand_assignment (tree to, tree from, int want_value)
    with no sequence point.  Will other languages need this to
    be more thorough?
 
-   If WANT_VALUE & 1 is 0, we return NULL, to make sure
-   to catch quickly any cases where the caller uses the value
-   and fails to set WANT_VALUE.
-
-   If WANT_VALUE & 2 is set, this is a store into a call param on the
+   If CALL_PARAM_P is nonzero, this is a store into a call param on the
    stack, and block moves may need to be treated specially.  */
 
 rtx
-store_expr (tree exp, rtx target, int want_value)
+store_expr (tree exp, rtx target, int call_param_p)
 {
   rtx temp;
   rtx alt_rtl = NULL_RTX;
-  rtx mark = mark_queue ();
   int dont_return_target = 0;
-  int dont_store_target = 0;
 
   if (VOID_TYPE_P (TREE_TYPE (exp)))
     {
       /* 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 (!call_param_p);
       expand_expr (exp, const0_rtx, VOIDmode, 0);
       return NULL_RTX;
     }
@@ -4043,9 +3874,8 @@ store_expr (tree exp, rtx target, int want_value)
       /* Perform first part of compound expression, then assign from second
         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);
+                  call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL);
+      return store_expr (TREE_OPERAND (exp, 1), target, call_param_p);
     }
   else if (TREE_CODE (exp) == COND_EXPR && GET_MODE (target) == BLKmode)
     {
@@ -4056,75 +3886,18 @@ 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 ();
+      store_expr (TREE_OPERAND (exp, 1), target, call_param_p);
       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 ();
+      store_expr (TREE_OPERAND (exp, 2), target, call_param_p);
       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_VOLATILE_P (target)
-          && GET_MODE (target) != BLKmode)
-    /* If target is in memory and caller wants value in a register instead,
-       arrange that.  Pass TARGET as target for expand_expr so that,
-       if EXP is another assignment, WANT_VALUE will be nonzero for it.
-       We know expand_expr will not use the target in that case.
-       Don't do this if TARGET is volatile because we are supposed
-       to write it and then read it.  */
-    {
-      temp = expand_expr (exp, target, GET_MODE (target),
-                         want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
-      if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)
-       {
-         /* If TEMP is already in the desired TARGET, only copy it from
-            memory and don't store it there again.  */
-         if (temp == target
-             || (rtx_equal_p (temp, target)
-                 && ! side_effects_p (temp) && ! side_effects_p (target)))
-           dont_store_target = 1;
-         temp = copy_to_reg (temp);
-       }
-      dont_return_target = 1;
+      return NULL_RTX;
     }
   else if (GET_CODE (target) == SUBREG && SUBREG_PROMOTED_VAR_P (target))
     /* If this is a scalar in a register that is stored in a wider mode
@@ -4134,15 +3907,17 @@ store_expr (tree exp, rtx target, int want_value)
     {
       rtx inner_target = 0;
 
-      /* If we don't want a value, we can do the conversion inside EXP,
-        which will often result in some optimizations.  Do the conversion
-        in two steps: first change the signedness, if needed, then
-        the extend.  But don't do this if the type of EXP is a subtype
-        of something else since then the conversion might involve
-        more than just converting modes.  */
-      if ((want_value & 1) == 0
-         && INTEGRAL_TYPE_P (TREE_TYPE (exp))
-         && TREE_TYPE (TREE_TYPE (exp)) == 0)
+      /* We can do the conversion inside EXP, which will often result
+        in some optimizations.  Do the conversion in two steps: first
+        change the signedness, if needed, then the extend.  But don't
+        do this if the type of EXP is a subtype of something else
+        since then the conversion might involve more than just
+        converting modes.  */
+      if (INTEGRAL_TYPE_P (TREE_TYPE (exp))
+         && TREE_TYPE (TREE_TYPE (exp)) == 0
+         && (!lang_hooks.reduce_bit_field_operations
+             || (GET_MODE_PRECISION (GET_MODE (target))
+                 == TYPE_PRECISION (TREE_TYPE (exp)))))
        {
          if (TYPE_UNSIGNED (TREE_TYPE (exp))
              != SUBREG_PROMOTED_UNSIGNED_P (target))
@@ -4159,15 +3934,7 @@ store_expr (tree exp, rtx target, int want_value)
        }
 
       temp = expand_expr (exp, inner_target, VOIDmode,
-                         want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
-
-      /* If TEMP is a MEM and we want a result value, make the access
-        now so it gets done only once.  Strictly speaking, this is
-        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)
-       temp = copy_to_reg (temp);
+                         call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL);
 
       /* If TEMP is a VOIDmode constant, use convert_modes to make
         sure that we properly convert it.  */
@@ -4183,31 +3950,12 @@ store_expr (tree exp, rtx target, int want_value)
       convert_move (SUBREG_REG (target), temp,
                    SUBREG_PROMOTED_UNSIGNED_P (target));
 
-      /* If we promoted a constant, change the mode back down to match
-        target.  Otherwise, the caller might get confused by a result whose
-        mode is larger than expected.  */
-
-      if ((want_value & 1) != 0 && GET_MODE (temp) != GET_MODE (target))
-       {
-         if (GET_MODE (temp) != VOIDmode)
-           {
-             temp = gen_lowpart_SUBREG (GET_MODE (target), temp);
-             SUBREG_PROMOTED_VAR_P (temp) = 1;
-             SUBREG_PROMOTED_UNSIGNED_SET (temp,
-               SUBREG_PROMOTED_UNSIGNED_P (target));
-           }
-         else
-           temp = convert_modes (GET_MODE (target),
-                                 GET_MODE (SUBREG_REG (target)),
-                                 temp, SUBREG_PROMOTED_UNSIGNED_P (target));
-       }
-
-      return want_value & 1 ? temp : NULL_RTX;
+      return NULL_RTX;
     }
   else
     {
       temp = expand_expr_real (exp, target, GET_MODE (target),
-                              (want_value & 2 
+                              (call_param_p
                                ? EXPAND_STACK_PARM : EXPAND_NORMAL),
                               &alt_rtl);
       /* Return TARGET if it's a specified hardware register.
@@ -4219,9 +3967,9 @@ store_expr (tree exp, rtx target, int want_value)
         or if we really want the correct value.  */
       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))
+         && CONSTANT_P (temp))
        dont_return_target = 1;
     }
 
@@ -4257,7 +4005,6 @@ store_expr (tree exp, rtx target, int want_value)
        || (temp != target && (side_effects_p (temp)
                              || 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.  */
@@ -4268,9 +4015,6 @@ store_expr (tree exp, rtx target, int want_value)
         bit-initialized.  */
       && expr_size (exp) != const0_rtx)
     {
-      emit_insns_enqueued_after_mark (mark);
-      target = protect_from_queue (target, 1);
-      temp = protect_from_queue (temp, 0);
       if (GET_MODE (temp) != GET_MODE (target)
          && GET_MODE (temp) != VOIDmode)
        {
@@ -4298,7 +4042,7 @@ store_expr (tree exp, rtx target, int want_value)
          if (GET_CODE (size) == CONST_INT
              && INTVAL (size) < TREE_STRING_LENGTH (exp))
            emit_block_move (target, temp, size,
-                            (want_value & 2
+                            (call_param_p
                              ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
          else
            {
@@ -4309,7 +4053,7 @@ store_expr (tree exp, rtx target, int want_value)
                              size_int (TREE_STRING_LENGTH (exp)));
              rtx copy_size_rtx
                = expand_expr (copy_size, NULL_RTX, VOIDmode,
-                              (want_value & 2
+                              (call_param_p
                                ? EXPAND_STACK_PARM : EXPAND_NORMAL));
              rtx label = 0;
 
@@ -4317,7 +4061,7 @@ store_expr (tree exp, rtx target, int want_value)
              copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx,
                                               TYPE_UNSIGNED (sizetype));
              emit_block_move (target, temp, copy_size_rtx,
-                              (want_value & 2
+                              (call_param_p
                                ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
 
              /* Figure out how much is left in TARGET that we have to clear.
@@ -4361,7 +4105,7 @@ store_expr (tree exp, rtx target, int want_value)
                         int_size_in_bytes (TREE_TYPE (exp)));
       else if (GET_MODE (temp) == BLKmode)
        emit_block_move (target, temp, expr_size (exp),
-                        (want_value & 2
+                        (call_param_p
                          ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
       else
        {
@@ -4371,24 +4115,7 @@ store_expr (tree exp, rtx target, int want_value)
        }
     }
 
-  /* If we don't want a value, return NULL_RTX.  */
-  if ((want_value & 1) == 0)
-    return NULL_RTX;
-
-  /* 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)
-    return temp;
-
-  /* Return TARGET itself if it is a hard register.  */
-  else if ((want_value & 1) != 0
-          && GET_MODE (target) != BLKmode
-          && ! (REG_P (target)
-                && REGNO (target) < FIRST_PSEUDO_REGISTER))
-    return copy_to_reg (target);
-
-  else
-    return target;
+  return NULL_RTX;
 }
 \f
 /* Examine CTOR.  Discover how many scalar fields are set to nonzero
@@ -4404,7 +4131,7 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
 
   nz_elts = 0;
   nc_elts = 0;
-  
+
   for (list = CONSTRUCTOR_ELTS (ctor); list; list = TREE_CHAIN (list))
     {
       tree value = TREE_VALUE (list);
@@ -4488,11 +4215,11 @@ count_type_elements (tree type)
        tree telts = array_type_nelts (type);
        if (telts && host_integerp (telts, 1))
          {
-           HOST_WIDE_INT n = tree_low_cst (telts, 1);
+           HOST_WIDE_INT n = tree_low_cst (telts, 1) + 1;
            HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type));
            if (n == 0)
              return 0;
-           if (max / n < m)
+           else if (max / n > m)
              return n * m;
          }
        return -1;
@@ -4530,8 +4257,7 @@ count_type_elements (tree type)
       return 2;
 
     case VECTOR_TYPE:
-      /* ??? This is broke.  We should encode the vector width in the tree.  */
-      return GET_MODE_NUNITS (TYPE_MODE (type));
+      return TYPE_VECTOR_SUBPARTS (type);
 
     case INTEGER_TYPE:
     case REAL_TYPE:
@@ -4550,17 +4276,17 @@ count_type_elements (tree type)
     case FUNCTION_TYPE:
     case LANG_TYPE:
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
 /* Return 1 if EXP contains mostly (3/4)  zeros.  */
 
-int
+static int
 mostly_zeros_p (tree exp)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR)
-    
+
     {
       HOST_WIDE_INT nz_elts, nc_elts, elts;
 
@@ -4601,9 +4327,9 @@ store_constructor_field (rtx target, unsigned HOST_WIDE_INT bitsize,
       /* 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
@@ -4613,7 +4339,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);
@@ -4623,8 +4349,7 @@ store_constructor_field (rtx target, unsigned HOST_WIDE_INT bitsize,
       store_constructor (exp, target, cleared, bitsize / BITS_PER_UNIT);
     }
   else
-    store_field (target, bitsize, bitpos, mode, exp, VOIDmode, 0, type,
-                alias_set);
+    store_field (target, bitsize, bitpos, mode, exp, type, alias_set);
 }
 
 /* Store the value of constructor EXP into the rtx TARGET.
@@ -4643,674 +4368,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 (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;
-       }
-
-      /* 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)))
-       {
-         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 && 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;
+       /* 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;
+         }
 
-         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 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;
+         }
 
-         if (offset)
-           {
-             rtx offset_rtx;
+        /* 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;
+         }
 
-             offset
-               = SUBSTITUTE_PLACEHOLDER_IN_EXPR (offset,
-                                                 make_tree (TREE_TYPE (exp),
-                                                            target));
+       if (! cleared)
+         emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
 
-             offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
-             if (GET_CODE (to_rtx) != MEM)
-               abort ();
+       /* 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 && 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 (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 (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;
-           }
+           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;
 
-         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;
-      tree elttype = TREE_TYPE (type);
-      int const_bounds_p;
-      HOST_WIDE_INT minelt = 0;
-      HOST_WIDE_INT maxelt = 0;
-      int icode = 0;
-      rtx *vector = NULL;
-      int elt_size = 0;
-      unsigned n_elts = 0;
-
-      if (TREE_CODE (type) == ARRAY_TYPE)
        domain = TYPE_DOMAIN (type);
-      else
-       /* Vectors do not have domains; look up the domain of
-          the array embedded in the debug representation type.
-          FIXME Would probably be more efficient to treat vectors
-          separately from arrays.  */
-       {
-         domain = TYPE_DEBUG_REPRESENTATION_TYPE (type);
-         domain = TYPE_DOMAIN (TREE_TYPE (TYPE_FIELDS (domain)));
-         if (REG_P (target) && VECTOR_MODE_P (GET_MODE (target)))
-           {
-             enum machine_mode mode = GET_MODE (target);
-
-             icode = (int) vec_init_optab->handlers[mode].insn_code;
-             if (icode != CODE_FOR_nothing)
-               {
-                 unsigned int i;
-
-                 elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
-                 n_elts = (GET_MODE_SIZE (mode) / elt_size);
-                 vector = alloca (n_elts);
-                 for (i = 0; i < n_elts; i++)
-                   vector [i] = CONST0_RTX (GET_MODE_INNER (mode));
-               }
-           }
-       }
-
-      const_bounds_p = (TYPE_MIN_VALUE (domain)
-                       && 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 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 || (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 && !vector)
-       {
-         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 && 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 (vector)
-               abort ();
-
-             /* 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
-               {
-                 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);
-                 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);
-
-                 /* Build the head of the loop.  */
-                 do_pending_stack_adjust ();
-                 emit_queue ();
-                 emit_label (loop_start);
-
-                 /* 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);
-
-                 /* Generate a conditional jump to exit the loop.  */
-                 exit_cond = build (LT_EXPR, integer_type_node,
-                                    index, hi_index);
-                 jumpif (exit_cond, loop_end);
-
-                 /* Update the loop counter, and jump to the head of
-                    the loop.  */
-                 expand_increment (build (PREINCREMENT_EXPR,
-                                          TREE_TYPE (index),
-                                          index, integer_one_node), 0, 0);
-                 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 (vector)
-               abort ();
-
-             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 (vector)
-           {
-             int pos;
+       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 (index != 0)
-               pos = tree_low_cst (index, 0) - minelt;
-             else
-               pos = i;
-             vector[pos] = expand_expr (value, NULL_RTX, VOIDmode, 0);
-           }
-         else
-           {
-             if (index != 0)
-               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));
-           }
-       }
-      if (vector)
-       {
-         emit_insn (GEN_FCN (icode) (target,
-                                     gen_rtx_PARALLEL (GET_MODE (target),
-                                                       gen_rtvec_v (n_elts, vector))));
-       }
-    }
-
-  /* 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.  */
+       /* 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);
+         }
 
-      /* Check for all zeros.  */
-      if (elt == NULL_TREE && size > 0)
-       {
-         if (!cleared)
-           clear_storage (target, GEN_INT (size));
-         return;
-       }
+       /* 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;
+         }
 
-      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));
+       if (!cleared && REG_P (target))
+         /* Inform later passes that the old value is dead.  */
+         emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
 
-      nbits = tree_low_cst (bitlength, 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);
 
-      /* 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;
-               }
+                   /* 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));
+                   
+                   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;
+      }
 
-             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 (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
+           
+           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)
@@ -5318,12 +5100,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
    BITSIZE bits, starting BITPOS bits from the start of TARGET.
    If MODE is VOIDmode, it means that we are storing into a bit-field.
 
-   If VALUE_MODE is VOIDmode, return nothing in particular.
-   UNSIGNEDP is not used in this case.
-
-   Otherwise, return an rtx for the value stored.  This rtx
-   has mode VALUE_MODE if that is convenient to do.
-   In this case, UNSIGNEDP must be nonzero if the value is an unsigned type.
+   Always return const0_rtx unless we have something particular to
+   return.
 
    TYPE is the type of the underlying object,
 
@@ -5333,8 +5111,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
 
 static rtx
 store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
-            enum machine_mode mode, tree exp, enum machine_mode value_mode,
-            int unsignedp, tree type, int alias_set)
+            enum machine_mode mode, tree exp, tree type, int alias_set)
 {
   HOST_WIDE_INT width_mask = 0;
 
@@ -5369,8 +5146,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
       if (bitsize != (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (target)))
        emit_move_insn (object, target);
 
-      store_field (blk_object, bitsize, bitpos, mode, exp, VOIDmode, 0, type,
-                  alias_set);
+      store_field (blk_object, bitsize, bitpos, mode, exp, type, alias_set);
 
       emit_move_insn (target, object);
 
@@ -5382,9 +5158,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, value_mode != VOIDmode);
+      gcc_assert (!bitpos);
+      return store_expr (exp, target, 0);
     }
 
   /* If the structure is in a register or if the component
@@ -5436,9 +5211,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,
@@ -5446,63 +5220,18 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
                                    / BITS_PER_UNIT),
                           BLOCK_OP_NORMAL);
 
-         return value_mode == VOIDmode ? const0_rtx : target;
+         return const0_rtx;
        }
 
       /* Store the value in the bitfield.  */
-      store_bit_field (target, bitsize, bitpos, mode, temp,
-                      int_size_in_bytes (type));
-
-      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)))
-           {
-             tree count;
-             enum machine_mode tmode;
-
-             tmode = GET_MODE (temp);
-             if (tmode == VOIDmode)
-               tmode = value_mode;
-
-             if (unsignedp)
-               return expand_and (tmode, temp,
-                                  gen_int_mode (width_mask, tmode),
-                                  NULL_RTX);
-
-             count = build_int_2 (GET_MODE_BITSIZE (tmode) - bitsize, 0);
-             temp = expand_shift (LSHIFT_EXPR, tmode, temp, count, 0, 0);
-             return expand_shift (RSHIFT_EXPR, tmode, temp, count, 0, 0);
-           }
+      store_bit_field (target, bitsize, bitpos, mode, temp);
 
-         return extract_bit_field (target, bitsize, bitpos, unsignedp,
-                                   NULL_RTX, value_mode, VOIDmode,
-                                   int_size_in_bytes (type));
-       }
       return const0_rtx;
     }
   else
     {
-      rtx addr = XEXP (target, 0);
-      rtx to_rtx = target;
-
-      /* If a value is wanted, it must be the lhs;
-        so make the address stable for multiple use.  */
-
-      if (value_mode != VOIDmode && !REG_P (addr)
-         && ! CONSTANT_ADDRESS_P (addr)
-         /* A frame-pointer reference is already stable.  */
-         && ! (GET_CODE (addr) == PLUS
-               && GET_CODE (XEXP (addr, 1)) == CONST_INT
-               && (XEXP (addr, 0) == virtual_incoming_args_rtx
-                   || XEXP (addr, 0) == virtual_stack_vars_rtx)))
-       to_rtx = replace_equiv_address (to_rtx, copy_to_reg (addr));
-
       /* Now build a reference to just the desired component.  */
-
-      to_rtx = adjust_address (target, mode, bitpos / BITS_PER_UNIT);
+      rtx to_rtx = adjust_address (target, mode, bitpos / BITS_PER_UNIT);
 
       if (to_rtx == target)
        to_rtx = copy_rtx (to_rtx);
@@ -5511,7 +5240,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
       if (!MEM_KEEP_ALIAS_SET_P (to_rtx) && MEM_ALIAS_SET (to_rtx) != 0)
        set_mem_alias_set (to_rtx, alias_set);
 
-      return store_expr (exp, to_rtx, value_mode != VOIDmode);
+      return store_expr (exp, to_rtx, 0);
     }
 }
 \f
@@ -5592,15 +5321,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
-           this_offset = SUBSTITUTE_PLACEHOLDER_IN_EXPR (this_offset, exp);
 
          offset = size_binop (PLUS_EXPR, offset, this_offset);
          bit_offset = size_binop (PLUS_EXPR, bit_offset,
@@ -5613,23 +5340,17 @@ 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, instantiate it with
-            the object; likewise for the component size.  */
-         index = SUBSTITUTE_PLACEHOLDER_IN_EXPR (index, exp);
-         unit_size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (unit_size, array);
+         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,
                                           convert (sizetype, index),
@@ -5677,6 +5398,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
@@ -5723,7 +5537,7 @@ force_operand (rtx value, rtx target)
   /* Check for subreg applied to an expression produced by loop optimizer.  */
   if (code == SUBREG
       && !REG_P (SUBREG_REG (value))
-      && GET_CODE (SUBREG_REG (value)) != MEM)
+      && !MEM_P (SUBREG_REG (value)))
     {
       value = simplify_gen_subreg (GET_MODE (value),
                                   force_reg (GET_MODE (SUBREG_REG (value)),
@@ -5834,7 +5648,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
@@ -5862,7 +5676,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
@@ -5879,7 +5692,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))))
@@ -5894,41 +5707,17 @@ safe_from_p (rtx x, tree exp, int top_p)
        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 testcase compiled
-     with optimization took about 28 minutes to compile -- even though it was
-     only a few lines long.  So we mark each SAVE_EXPR we see with TREE_PRIVATE
-     and turn that off when we are done.  We keep a list of the SAVE_EXPRs
-     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)))
     {
-    case 'd':
+    case tcc_declaration:
       exp_rtl = DECL_RTL_IF_SET (exp);
       break;
 
-    case 'c':
+    case tcc_constant:
       return 1;
 
-    case 'x':
+    case tcc_exceptional:
       if (TREE_CODE (exp) == TREE_LIST)
        {
          while (1)
@@ -5947,17 +5736,25 @@ safe_from_p (rtx x, tree exp, int top_p)
       else
        return 0;
 
-    case '2':
-    case '<':
+    case tcc_statement:
+      /* 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 tcc_binary:
+    case tcc_comparison:
       if (!safe_from_p (x, TREE_OPERAND (exp, 1), 0))
        return 0;
       /* Fall through.  */
 
-    case '1':
+    case tcc_unary:
       return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
 
-    case 'e':
-    case 'r':
+    case tcc_expression:
+    case tcc_reference:
       /* Now do code-specific tests.  EXP_RTL is set to any rtx we find in
         the expression.  If it is set, we conflict iff we are that rtx or
         both are in memory.  Otherwise, we check all operands of the
@@ -5980,15 +5777,17 @@ 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);
            }
          break;
 
+       case MISALIGNED_INDIRECT_REF:
+       case ALIGN_INDIRECT_REF:
        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;
@@ -5998,52 +5797,17 @@ safe_from_p (rtx x, tree exp, int top_p)
          /* Assume that the call will clobber all hard registers and
             all of memory.  */
          if ((REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
-             || GET_CODE (x) == MEM)
+             || 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;
@@ -6065,6 +5829,11 @@ safe_from_p (rtx x, tree exp, int top_p)
          >= (unsigned int) LAST_AND_UNUSED_TREE_CODE
          && !lang_hooks.safe_from_p (x, exp))
        return 0;
+      break;
+
+    case tcc_type:
+      /* Should never get a type here.  */
+      gcc_unreachable ();
     }
 
   /* If we have an rtl, find any enclosed object.  Then see if we conflict
@@ -6082,7 +5851,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)));
     }
@@ -6091,22 +5860,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;
-    }
-}
 \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.  */
@@ -6189,9 +5942,9 @@ highest_pow2_factor_for_target (tree target, tree exp)
 
   factor = highest_pow2_factor (exp);
   if (TREE_CODE (target) == COMPONENT_REF)
-    target_align = DECL_ALIGN (TREE_OPERAND (target, 1)) / BITS_PER_UNIT;
+    target_align = DECL_ALIGN_UNIT (TREE_OPERAND (target, 1));
   else
-    target_align = TYPE_ALIGN (TREE_TYPE (target)) / BITS_PER_UNIT;
+    target_align = TYPE_ALIGN_UNIT (TREE_TYPE (target));
   return MAX (factor, target_align);
 }
 \f
@@ -6212,50 +5965,20 @@ expand_var (tree var)
       ? !TREE_ASM_WRITTEN (var)
       : !DECL_RTL_SET_P (var))
     {
-      if (TREE_CODE (var) == VAR_DECL && DECL_DEFER_OUTPUT (var))
-       {
-         /* Prepare a mem & address for the decl.  */
-         rtx x;
-                   
-         if (TREE_STATIC (var))
-           abort ();
-
-         x = gen_rtx_MEM (DECL_MODE (var),
-                          gen_reg_rtx (Pmode));
-
-         set_mem_attributes (x, var, 1);
-         SET_DECL_RTL (var, x);
-       }
+      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, NULL, 0, 0);
-      else if (TREE_CODE (var) == TYPE_DECL
-              || TREE_CODE (var) == CONST_DECL
-              || TREE_CODE (var) == FUNCTION_DECL
-              || TREE_CODE (var) == LABEL_DECL)
-       /* No expansion needed.  */;
+       rest_of_decl_compilation (var, 0, 0);
       else
-       abort ();
-    }
-}
-
-/* Expands declarations of variables in list VARS.  */
-
-static void
-expand_vars (tree vars)
-{
-  for (; vars; vars = TREE_CHAIN (vars))
-    {
-      tree var = vars;
-
-      if (DECL_EXTERNAL (var))
-       continue;
-
-      expand_var (var);
-      expand_decl_init (var);
+       /* 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);
     }
 }
 
@@ -6287,6 +6010,171 @@ expand_operands (tree exp0, tree exp1, rtx target, rtx *op0, rtx *op1,
 }
 
 \f
+/* A subroutine of expand_expr_addr_expr.  Evaluate the address of EXP.
+   The TARGET, TMODE and MODIFIER arguments are as for expand_expr.  */
+
+static rtx
+expand_expr_addr_expr_1 (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
+      || CONSTANT_CLASS_P (exp))
+    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_1 (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 (DECL_P (exp) && !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_1 (inner, subtarget, tmode, modifier);
+
+  if (offset)
+    {
+      rtx tmp;
+
+      if (modifier != EXPAND_NORMAL)
+       result = force_operand (result, NULL);
+      tmp = expand_expr (offset, NULL, tmode, EXPAND_NORMAL);
+
+      result = convert_memory_address (tmode, result);
+      tmp = convert_memory_address (tmode, tmp);
+
+      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) == 0);
+
+      result = plus_constant (result, bitpos / BITS_PER_UNIT);
+      if (modifier < EXPAND_SUM)
+       result = force_operand (result, target);
+    }
+
+  return result;
+}
+
+/* A subroutine of expand_expr.  Evaluate EXP, which is an ADDR_EXPR.
+   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)
+{
+  enum machine_mode rmode;
+  rtx result;
+
+  /* Target mode of VOIDmode says "whatever's natural".  */
+  if (tmode == VOIDmode)
+    tmode = TYPE_MODE (TREE_TYPE (exp));
+
+  /* We can get called with some Weird Things if the user does silliness
+     like "(short) &a".  In that case, convert_memory_address won't do
+     the right thing, so ignore the given target mode.  */
+  if (tmode != Pmode && tmode != ptr_mode)
+    tmode = Pmode;
+
+  result = expand_expr_addr_expr_1 (TREE_OPERAND (exp, 0), target,
+                                   tmode, modifier);
+
+  /* Despite expand_expr claims concerning ignoring TMODE when not
+     strictly convenient, stuff breaks if we don't honor it.  Note
+     that combined with the above, we only do this for pointer modes.  */
+  rmode = GET_MODE (result);
+  if (rmode == VOIDmode)
+    rmode = tmode;
+  if (rmode != tmode)
+    result = convert_memory_address (tmode, result);
+
+  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.
@@ -6327,7 +6215,7 @@ expand_operands (tree exp0, tree exp1, rtx target, rtx *op0, rtx *op1,
    marked TARGET so that it's safe from being trashed by libcalls.  We
    don't want to use TARGET for anything but the final result;
    Intermediate values must go elsewhere.   Additionally, calls to
-   emit_block_move will be flagged with BLOCK_OP_CALL_PARM.  
+   emit_block_move will be flagged with BLOCK_OP_CALL_PARM.
 
    If EXP is a VAR_DECL whose DECL_RTL was a MEM with an invalid
    address, and ALT_RTL is non-NULL, then *ALT_RTL is set to the
@@ -6362,11 +6250,11 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
     }
 
   /* If this is an expression of some kind and it has an associated line
-     number, then emit the line number before expanding the expression. 
+     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 
+     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))
@@ -6374,10 +6262,9 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
       location_t saved_location = input_location;
       input_location = EXPR_LOCATION (exp);
       emit_line_note (input_location);
-      
+
       /* Record where the insns produced belong.  */
-      if (cfun->dont_emit_block_notes)
-       record_block_change (TREE_BLOCK (exp));
+      record_block_change (TREE_BLOCK (exp));
 
       ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl);
 
@@ -6392,9 +6279,9 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
      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; 
+      for (insn = next_real_insn (last); insn;
           insn = next_real_insn (insn))
        {
          if (! find_reg_note (insn, REG_EH_REGION, NULL_RTX)
@@ -6402,7 +6289,7 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
                 may_trap_p instruction may throw.  */
              && GET_CODE (PATTERN (insn)) != CLOBBER
              && GET_CODE (PATTERN (insn)) != USE
-             && (GET_CODE (insn) == CALL_INSN || may_trap_p (PATTERN (insn))))
+             && (CALL_P (insn) || may_trap_p (PATTERN (insn))))
            {
              REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION, GEN_INT (rn),
                                                  REG_NOTES (insn));
@@ -6426,17 +6313,34 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
   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))
 
   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;
+    }
 
   /* 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
@@ -6458,17 +6362,18 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          && 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)
+      if (TREE_CODE_CLASS (code) == tcc_unary
+         || code == COMPONENT_REF || code == INDIRECT_REF)
        return expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
                            modifier);
 
-      else if (TREE_CODE_CLASS (code) == '2' || TREE_CODE_CLASS (code) == '<'
+      else if (TREE_CODE_CLASS (code) == tcc_binary
+              || TREE_CODE_CLASS (code) == tcc_comparison
               || code == ARRAY_REF || code == ARRAY_RANGE_REF)
        {
          expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, modifier);
@@ -6522,15 +6427,11 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        return temp;
       }
 
-    case PARM_DECL:
-      if (!DECL_RTL_SET_P (exp))
-       {
-         error ("%Jprior parameter's size depends on '%D'", 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.  */
@@ -6543,8 +6444,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
     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
@@ -6558,39 +6458,20 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* 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);
-
-      if (context != 0 && context != current_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
+      if (MEM_P (DECL_RTL (exp))
               && REG_P (XEXP (DECL_RTL (exp), 0)))
        temp = validize_mem (DECL_RTL (exp));
 
@@ -6598,7 +6479,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         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
@@ -6617,7 +6498,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         if the address is a register.  */
       if (temp != 0)
        {
-         if (GET_CODE (temp) == MEM && REG_P (XEXP (temp, 0)))
+         if (MEM_P (temp) && REG_P (XEXP (temp, 0)))
            mark_reg_pointer (XEXP (temp, 0), DECL_ALIGN (exp));
 
          return temp;
@@ -6630,12 +6511,13 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       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;
@@ -6661,7 +6543,13 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       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);
@@ -6697,119 +6585,53 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          if (op0 != rtarg)
            emit_move_insn (rtarg, op0);
          if (op1 != itarg)
-           emit_move_insn (itarg, op1);
-
-         return original_target;
-       }
-
-      /* ... fall through ...  */
-
-    case STRING_CST:
-      temp = output_constant_def (exp, 1);
-
-      /* temp contains a constant address.
-        On RISC machines where a constant address isn't valid,
-        make some insns to get that address into a register.  */
-      if (modifier != EXPAND_CONST_ADDRESS
-         && modifier != EXPAND_INITIALIZER
-         && modifier != EXPAND_SUM
-         && (! memory_address_p (mode, XEXP (temp, 0))
-             || flag_force_addr))
-       return replace_equiv_address (temp,
-                                     copy_rtx (XEXP (temp, 0)));
-      return temp;
-
-    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;
-
-      if (context == current_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 && REG_P (temp))
-           {
-             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 && REG_P (temp))
-           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 (REG_P (temp) && 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);
+           emit_move_insn (itarg, op1);
 
-         TREE_USED (exp) = 1;
+         return original_target;
        }
 
-      /* 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.  */
+      /* ... fall through ...  */
 
-      if (REG_P (SAVE_EXPR_RTL (exp))
-         && 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;
-       }
+    case STRING_CST:
+      temp = output_constant_def (exp, 1);
 
-      return SAVE_EXPR_RTL (exp);
+      /* temp contains a constant address.
+        On RISC machines where a constant address isn't valid,
+        make some insns to get that address into a register.  */
+      if (modifier != EXPAND_CONST_ADDRESS
+         && modifier != EXPAND_INITIALIZER
+         && modifier != EXPAND_SUM
+         && (! memory_address_p (mode, XEXP (temp, 0))
+             || flag_force_addr))
+       return replace_equiv_address (temp,
+                                     copy_rtx (XEXP (temp, 0)));
+      return temp;
 
-    case UNSAVE_EXPR:
+    case SAVE_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;
+       tree val = TREE_OPERAND (exp, 0);
+       rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl);
+
+       if (!SAVE_EXPR_RESOLVED_P (exp))
+         {
+           /* 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);
+         }
+
+        return ret;
       }
 
     case GOTO_EXPR:
@@ -6819,87 +6641,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        expand_computed_goto (TREE_OPERAND (exp, 0));
       return const0_rtx;
 
-    /* These are lowered during gimplification, so we should never ever
-       see them here.  */
-    case LOOP_EXPR:
-    case EXIT_EXPR:
-      abort ();
-
-    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 BIND_EXPR:
-      {
-       tree block = BIND_EXPR_BLOCK (exp);
-       int mark_ends;
-
-       if (TREE_CODE (BIND_EXPR_BODY (exp)) != RTL_EXPR)
-         {
-           /* If we're in functions-as-trees mode, this BIND_EXPR represents
-              the block, so we need to emit NOTE_INSN_BLOCK_* notes.  */
-           mark_ends = (block != NULL_TREE);
-           expand_start_bindings_and_block (mark_ends ? 0 : 2, block);
-         }
-       else
-         {
-           /* If we're not in functions-as-trees mode, we've already emitted
-              those notes into our RTL_EXPR, so we just want to splice our BLOCK
-              into the enclosing one.  */
-           mark_ends = 0;
-
-           /* Need to open a binding contour here because
-              if there are any cleanups they must be contained here.  */
-           expand_start_bindings_and_block (2, NULL_TREE);
-
-           /* Mark the corresponding BLOCK for output in its proper place.  */
-           if (block)
-             {
-               if (TREE_USED (block))
-                 abort ();
-               lang_hooks.decls.insert_block (block);
-             }
-         }
-
-       /* If VARS have not yet been expanded, expand them now.  */
-       expand_vars (BIND_EXPR_VARS (exp));
-
-       /* TARGET was clobbered early in this function.  The correct
-          indicator or whether or not we need the value of this 
-          expression is the IGNORE variable.  */
-       temp = expand_expr (BIND_EXPR_BODY (exp),
-                           ignore ? const0_rtx : target,
-                           tmode, modifier);
-
-       expand_end_bindings (BIND_EXPR_VARS (exp), mark_ends, 0);
-
-       return temp;
-      }
-
-    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);
-      if (alt_rtl)
-       *alt_rtl = RTL_EXPR_ALT_RTL (exp);
-      return RTL_EXPR_RTL (exp);
-
     case CONSTRUCTOR:
       /* If we don't need the result, just ensure we evaluate any
         subexpressions.  */
@@ -6966,9 +6707,16 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          return target;
        }
 
+    case MISALIGNED_INDIRECT_REF:
+    case ALIGN_INDIRECT_REF:
     case INDIRECT_REF:
       {
        tree exp1 = TREE_OPERAND (exp, 0);
+       tree orig;
+
+       if (code == MISALIGNED_INDIRECT_REF
+           && !targetm.vectorize.misaligned_mem_ok (mode))
+         abort ();
 
        if (modifier != EXPAND_WRITE)
          {
@@ -6981,32 +6729,34 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
        op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
        op0 = memory_address (mode, op0);
+
+       if (code == ALIGN_INDIRECT_REF)
+         {
+           int align = TYPE_ALIGN_UNIT (type);
+           op0 = gen_rtx_AND (Pmode, op0, GEN_INT (-align));
+           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:
 
-#ifdef ENABLE_CHECKING
-      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) != ARRAY_TYPE)
-       abort ();
-#endif
-
       {
        tree array = TREE_OPERAND (exp, 0);
-       tree domain = TYPE_DOMAIN (TREE_TYPE (array));
-       tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
+       tree low_bound = array_ref_low_bound (exp);
        tree index = convert (sizetype, TREE_OPERAND (exp, 1));
        HOST_WIDE_INT i;
 
+       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
@@ -7146,8 +6896,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                    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);
@@ -7176,8 +6926,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        /* 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
@@ -7213,29 +6962,17 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
           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)
@@ -7243,8 +6980,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            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)
@@ -7273,12 +7009,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
        /* 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);
@@ -7291,8 +7027,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
           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;
          }
 
@@ -7314,7 +7050,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            || (mode1 != BLKmode
                && (((TYPE_ALIGN (TREE_TYPE (tem)) < GET_MODE_ALIGNMENT (mode)
                      || (bitpos % GET_MODE_ALIGNMENT (mode) != 0)
-                     || (GET_CODE (op0) == MEM
+                     || (MEM_P (op0)
                          && (MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode1)
                              || (bitpos % GET_MODE_ALIGNMENT (mode1) != 0))))
                     && ((modifier == EXPAND_CONST_ADDRESS
@@ -7326,16 +7062,16 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
               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);
 
@@ -7349,10 +7085,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
                /* 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 ();
+               gcc_assert (MEM_P (op0)
+                           && (!target || MEM_P (target))
+                           && !(bitpos % BITS_PER_UNIT));
 
                emit_block_move (target,
                                 adjust_address (op0, VOIDmode,
@@ -7367,14 +7102,13 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
            op0 = validize_mem (op0);
 
-           if (GET_CODE (op0) == MEM && REG_P (XEXP (op0, 0)))
+           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
@@ -7441,179 +7175,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        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 = TYPE_UNSIGNED (TREE_TYPE (index));
-       tree set_type = TREE_TYPE (set);
-       tree set_low_bound = TYPE_MIN_VALUE (TYPE_DOMAIN (set_type));
-       tree set_high_bound = TYPE_MAX_VALUE (TYPE_DOMAIN (set_type));
-       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.  */
@@ -7636,7 +7199,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case NON_LVALUE_EXPR:
     case NOP_EXPR:
     case CONVERT_EXPR:
-    case REFERENCE_EXPR:
       if (TREE_OPERAND (exp, 0) == error_mark_node)
        return const0_rtx;
 
@@ -7664,23 +7226,25 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                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 (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);
+                       modifier == EXPAND_STACK_PARM);
+
          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),
+                          type, 0);
+           }
 
          /* Return the entire union.  */
          return target;
@@ -7698,10 +7262,11 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
              && 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;
 
@@ -7747,7 +7312,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
               && 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
@@ -7755,8 +7320,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
             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
@@ -7772,7 +7336,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         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);
 
@@ -7789,8 +7353,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                                                    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,
@@ -7809,11 +7372,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       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
@@ -7826,10 +7385,10 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
       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);
 
@@ -7869,7 +7428,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
              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
@@ -7902,7 +7461,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
              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);
            }
        }
 
@@ -7924,7 +7483,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
       expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
                       subtarget, &op0, &op1, modifier);
-      return simplify_gen_binary (PLUS, mode, op0, op1);
+      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
@@ -7942,15 +7501,11 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          /* 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
@@ -7966,7 +7521,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       if (GET_CODE (op1) == CONST_INT)
        {
          op1 = negate_rtx (mode, op1);
-         return simplify_gen_binary (PLUS, mode, op0, op1);
+         return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
        }
 
       goto binop2;
@@ -7998,9 +7553,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          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 (modifier == EXPAND_STACK_PARM)
@@ -8054,7 +7609,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                    expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
                                     TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
                                     NULL_RTX, &op0, &op1, 0);
-                 goto binop2;
+                 goto binop3;
                }
              else if (other_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
                       && innermode == word_mode)
@@ -8078,13 +7633,13 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                                                      zextend_p);
                  if (htem != hipart)
                    emit_move_insn (hipart, htem);
-                 return temp;
+                 return REDUCE_BIT_FIELD (temp);
                }
            }
        }
       expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
                       subtarget, &op0, &op1, 0);
-      return expand_mult (mode, op0, op1, target, unsignedp);
+      return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp));
 
     case TRUNC_DIV_EXPR:
     case FLOOR_DIV_EXPR:
@@ -8107,12 +7662,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       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:
@@ -8128,7 +7683,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     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);
@@ -8155,12 +7710,10 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       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);
@@ -8168,9 +7721,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        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.  */
@@ -8185,7 +7737,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       target = original_target;
       if (target == 0
          || modifier == EXPAND_STACK_PARM
-         || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
+         || (MEM_P (target) && MEM_VOLATILE_P (target))
          || GET_MODE (target) != mode
          || (REG_P (target)
              && REGNO (target) < FIRST_PSEUDO_REGISTER))
@@ -8196,10 +7748,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* First try to do it with a special MIN or MAX instruction.
         If that does not win, use a conditional jump to select the proper
         value.  */
-      this_optab = (unsignedp
-                   ? (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)
@@ -8208,7 +7757,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* 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.  */
@@ -8250,8 +7799,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
       temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
-      if (temp == 0)
-       abort ();
+      gcc_assert (temp);
       return temp;
 
       /* ??? Can optimize bitwise operations with one arg constant.
@@ -8268,18 +7816,18 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         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:
@@ -8354,12 +7902,10 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          return temp;
        }
 
-      /* If no set-flag instruction, must generate a conditional
-        store into a temporary variable.  Drop through
-        and handle this like && and ||.  */
+      /* 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
@@ -8371,527 +7917,112 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
 
       if (target)
-       emit_clr_insn (target);
+       emit_move_insn (target, const0_rtx);
 
       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_real (TREE_OPERAND (exp, 1),
-                              (ignore ? const0_rtx : target),
-                              VOIDmode, modifier, alt_rtl);
-
-    case STATEMENT_LIST:
-      {
-       tree_stmt_iterator iter;
-
-       if (!ignore)
-         abort ();
-
-       for (iter = tsi_start (exp); !tsi_end_p (iter); tsi_next (&iter))
-         expand_expr (tsi_stmt (iter), const0_rtx, VOIDmode, modifier);
-      }
-      return const0_rtx;
-
-    case COND_EXPR:
-      /* If it's void, we don't need to worry about computing a value.  */
-      if (VOID_TYPE_P (TREE_TYPE (exp)))
-       {
-         tree pred = TREE_OPERAND (exp, 0);
-         tree then_ = TREE_OPERAND (exp, 1);
-         tree else_ = TREE_OPERAND (exp, 2);
-
-         /* If we do not have any pending cleanups or stack_levels
-            to restore, and at least one arm of the COND_EXPR is a
-            GOTO_EXPR to a local label, then we can emit more efficient
-            code by using jumpif/jumpifnot instead of the 'if' machinery.  */
-         if (! optimize
-             || containing_blocks_have_cleanups_or_stack_level ())
-           ;
-         else if (TREE_CODE (then_) == GOTO_EXPR
-                  && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
-           {
-             jumpif (pred, label_rtx (GOTO_DESTINATION (then_)));
-             return expand_expr (else_, const0_rtx, VOIDmode, 0);
-           }
-         else if (TREE_CODE (else_) == GOTO_EXPR
-                  && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)
-           {
-             jumpifnot (pred, label_rtx (GOTO_DESTINATION (else_)));
-             return expand_expr (then_, const0_rtx, VOIDmode, 0);
-           }
-
-         /* Just use the 'if' machinery.  */
-         expand_start_cond (pred, 0);
-         start_cleanup_deferral ();
-         expand_expr (then_, const0_rtx, VOIDmode, 0);
-
-         exp = else_;
-
-         /* Iterate over 'else if's instead of recursing.  */
-         for (; TREE_CODE (exp) == COND_EXPR; exp = TREE_OPERAND (exp, 2))
-           {
-             expand_start_else ();
-             if (EXPR_HAS_LOCATION (exp))
-               {
-                 emit_line_note (EXPR_LOCATION (exp));
-                 if (cfun->dont_emit_block_notes)
-                   record_block_change (TREE_BLOCK (exp));
-               }
-             expand_elseif (TREE_OPERAND (exp, 0));
-             expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, 0);
-           }
-         /* Don't emit the jump and label if there's no 'else' clause.  */
-         if (TREE_SIDE_EFFECTS (exp))
-           {
-             expand_start_else ();
-             expand_expr (exp, const0_rtx, VOIDmode, 0);
-           }
-         end_cleanup_deferral ();
-         expand_end_cond ();
-         return const0_rtx;
-       }
-
-      /* If we would have a "singleton" (see below) were it not for a
-        conversion in each arm, bring that conversion back out.  */
-      if (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
-         && 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 && REG_P (original_target)
-                        && REGNO (original_target) >= FIRST_PSEUDO_REGISTER
-                        && original_target == var_rtx (singleton)))
-                && GET_MODE (original_target) == mode
-#ifdef HAVE_conditional_move
-                && (! can_conditionally_move_p (mode)
-                    || REG_P (original_target)
-                    || 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))
-                   || (REG_P (temp)
-                       && 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 (REG_P (temp)
-               && 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 ();
-           if (TREE_TYPE (TREE_OPERAND (exp, 2)) != void_type_node)
-             store_expr (TREE_OPERAND (exp, 2), temp,
-                         modifier == EXPAND_STACK_PARM ? 2 : 0);
-           else
-             expand_expr (TREE_OPERAND (exp, 2),
-                          ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
-           op1 = op0;
-         }
-       else if (temp
-                && 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 (REG_P (temp)
-               && 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 ();
-           if (TREE_TYPE (TREE_OPERAND (exp, 1)) != void_type_node)
-             store_expr (TREE_OPERAND (exp, 1), temp,
-                         modifier == EXPAND_STACK_PARM ? 2 : 0);
-           else
-             expand_expr (TREE_OPERAND (exp, 1),
-                          ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
-           op1 = op0;
-         }
-       else
-         {
-           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;
-      }
-
-    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.
-
-          We guarantee that the expression will either be constructed
-          or copied into our original target.  */
-
-       tree slot = TREE_OPERAND (exp, 0);
-       tree cleanups = NULL_TREE;
-       tree exp1;
-
-       if (TREE_CODE (slot) != VAR_DECL)
-         abort ();
-
-       if (! ignore)
-         target = original_target;
-
-       /* 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 (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);
-               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);
-             }
-         }
-
-       exp1 = TREE_OPERAND (exp, 3) = TREE_OPERAND (exp, 1);
-       /* Mark it as expanded.  */
-       TREE_OPERAND (exp, 1) = NULL_TREE;
-
-       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);
+
+       emit_jump_insn (gen_jump (op1));
+       emit_barrier ();
+       emit_label (op0);
+       store_expr (TREE_OPERAND (exp, 2), temp,
+                 modifier == EXPAND_STACK_PARM);
+
+       emit_label (op1);
+       OK_DEFER_POP;
+       return temp;
+
+    case VEC_COND_EXPR:
+       target = expand_vec_cond_expr (exp, target);
+       return target;
 
     case MODIFY_EXPR:
       {
-       /* If lhs is complex, expand calls in rhs before computing it.
-          That's so we don't compute a pointer and save it over a
-          call.  If lhs is simple, compute it first so we can give it
-          as a target if the rhs is just a call.  This avoids an
-          extra temp and copy and that prevents a partial-subsumption
-          which makes bad code.  Actually we could treat
-          component_ref's of vars like vars.  */
-
        tree lhs = TREE_OPERAND (exp, 0);
        tree rhs = TREE_OPERAND (exp, 1);
 
-       temp = 0;
+       gcc_assert (ignore);
 
        /* Check for |= or &= of a bitfield of size one into another bitfield
           of size 1.  In this case, (unless we need the result of the
@@ -8901,8 +8032,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
           ??? At this point, we can't get a BIT_FIELD_REF here.  But if
           things change so we do, this code should be enhanced to
           support it.  */
-       if (ignore
-           && TREE_CODE (lhs) == COMPONENT_REF
+       if (TREE_CODE (lhs) == COMPONENT_REF
            && (TREE_CODE (rhs) == BIT_IOR_EXPR
                || TREE_CODE (rhs) == BIT_AND_EXPR)
            && TREE_OPERAND (rhs, 0) == lhs
@@ -8918,16 +8048,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            expand_assignment (lhs, convert (TREE_TYPE (rhs),
                                             (TREE_CODE (rhs) == BIT_IOR_EXPR
                                              ? integer_one_node
-                                             : integer_zero_node)),
-                              0);
+                                             : integer_zero_node)));
            do_pending_stack_adjust ();
            emit_label (label);
            return const0_rtx;
          }
 
-       temp = expand_assignment (lhs, rhs, ! ignore);
+       expand_assignment (lhs, rhs);
 
-       return temp;
+       return const0_rtx;
       }
 
     case RETURN_EXPR:
@@ -8937,163 +8066,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        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;
-      /* If we are taking the address of something erroneous, just
-        return a zero.  */
-      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 (REG_P (op0) || 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);
-             if (GET_MODE (op0) == Pmode && mode == ptr_mode)
-               op0 = convert_memory_address (ptr_mode, op0);
-             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
-         && !REG_P (op0)
-         && modifier != EXPAND_CONST_ADDRESS
-         && modifier != EXPAND_INITIALIZER
-         && modifier != EXPAND_SUM)
-       op0 = force_reg (Pmode, op0);
-
-      if (REG_P (op0)
-         && ! REG_USERVAR_P (op0))
-       mark_reg_pointer (op0, TYPE_ALIGN (TREE_TYPE (type)));
-
-      if (GET_MODE (op0) == Pmode && mode == ptr_mode)
-       op0 = convert_memory_address (ptr_mode, op0);
-
-      return op0;
-
-    case ENTRY_VALUE_EXPR:
-      abort ();
+      return expand_expr_addr_expr (exp, target, tmode, modifier);
 
     /* COMPLEX type for Extended Pascal & Fortran  */
     case COMPLEX_EXPR:
@@ -9137,143 +8111,38 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       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_handler (handler);
-
-       return op0;
-      }
-
     case CATCH_EXPR:
-      expand_start_catch (CATCH_TYPES (exp));
-      expand_expr (CATCH_BODY (exp), const0_rtx, VOIDmode, 0);
-      expand_end_catch ();
-      return const0_rtx;
-
     case EH_FILTER_EXPR:
-      /* Should have been handled in expand_eh_handler.  */
-      abort ();
-
     case TRY_FINALLY_EXPR:
-      {
-       tree try_block = TREE_OPERAND (exp, 0);
-       tree finally_block = TREE_OPERAND (exp, 1);
-
-        if ((!optimize && lang_protect_cleanup_actions == NULL)
-           || unsafe_for_reeval (finally_block) > 1)
-         {
-           /* In this case, wrapping FINALLY_BLOCK in an UNSAVE_EXPR
-              is not sufficient, so we cannot expand the block twice.
-              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);
@@ -9284,111 +8153,93 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     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_start_case (0, SWITCH_COND (exp), integer_type_node,
-                        "switch");
-      if (SWITCH_BODY (exp))
-        expand_expr_stmt (SWITCH_BODY (exp));
-      if (SWITCH_LABELS (exp))
-       {
-         tree duplicate = 0;
-         tree vec = SWITCH_LABELS (exp);
-         size_t i, n = TREE_VEC_LENGTH (vec);
-
-         for (i = 0; i < n; ++i)
-           {
-             tree elt = TREE_VEC_ELT (vec, i);
-             tree controlling_expr_type = TREE_TYPE (SWITCH_COND (exp));
-             tree min_value = TYPE_MIN_VALUE (controlling_expr_type);
-             tree max_value = TYPE_MAX_VALUE (controlling_expr_type);
-             
-             tree case_low = CASE_LOW (elt);
-             tree case_high = CASE_HIGH (elt) ? CASE_HIGH (elt) : case_low;
-             if (case_low && case_high)
-               {
-                 /* Case label is less than minimum for type.  */
-                 if ((tree_int_cst_compare (case_low, min_value) < 0)
-                     && (tree_int_cst_compare (case_high, min_value) < 0))
-                   {
-                     warning ("case label value %d is less than minimum value for type",
-                              TREE_INT_CST (case_low));
-                     continue;
-                   }
-                 
-                 /* Case value is greater than maximum for type.  */
-                 if ((tree_int_cst_compare (case_low, max_value) > 0)
-                     && (tree_int_cst_compare (case_high, max_value) > 0))
-                   {
-                     warning ("case label value %d exceeds maximum value for type",
-                              TREE_INT_CST (case_high));
-                     continue;
-                   }
-                 
-                 /* Saturate lower case label value to minimum.  */
-                 if ((tree_int_cst_compare (case_high, min_value) >= 0)
-                     && (tree_int_cst_compare (case_low, min_value) < 0))
-                   {
-                     warning ("lower value %d in case label range less than minimum value for type",
-                              TREE_INT_CST (case_low));
-                     case_low = min_value;
-                   }
-                 
-                 /* Saturate upper case label value to maximum.  */
-                 if ((tree_int_cst_compare (case_low, max_value) <= 0)
-                     && (tree_int_cst_compare (case_high, max_value) > 0))
-                   {
-                     warning ("upper value %d in case label range exceeds maximum value for type",
-                              TREE_INT_CST (case_high));
-                     case_high = max_value;
-                   }
-               }
-             
-             add_case_node (case_low, case_high, CASE_LABEL (elt), &duplicate, true);
-             if (duplicate)
-               abort ();
-           }
-       }
-      expand_end_case_type (SWITCH_COND (exp), TREE_TYPE (exp));
+      expand_case (exp);
       return const0_rtx;
 
     case LABEL_EXPR:
       expand_label (TREE_OPERAND (exp, 0));
       return const0_rtx;
 
-    case CASE_LABEL_EXPR:
-      {
-       tree duplicate = 0;
-       add_case_node (CASE_LOW (exp), CASE_HIGH (exp), CASE_LABEL (exp),
-                      &duplicate, false);
-       if (duplicate)
-         abort ();
-       return const0_rtx;
-      }
-
     case ASM_EXPR:
       expand_asm_expr (exp);
       return const0_rtx;
 
+    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);
+
+    case REALIGN_LOAD_EXPR:
+      {
+        tree oprnd0 = TREE_OPERAND (exp, 0); 
+        tree oprnd1 = TREE_OPERAND (exp, 1);
+        tree oprnd2 = TREE_OPERAND (exp, 2);
+        rtx op2;
+
+        this_optab = optab_for_tree_code (code, type);
+        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
+        op2 = expand_expr (oprnd2, NULL_RTX, VOIDmode, 0);
+        temp = expand_ternary_op (mode, this_optab, op0, op1, op2, 
+                                 target, unsignedp);
+        if (temp == 0)
+          abort ();
+        return temp;
+      }
+
+
     default:
       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:
   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
@@ -9408,7 +8259,7 @@ is_aligning_offset (tree offset, tree exp)
      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), 
+      || 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;
@@ -9442,20 +8293,31 @@ is_aligning_offset (tree offset, tree exp)
 tree
 string_constant (tree arg, tree *ptr_offset)
 {
+  tree array, offset;
   STRIP_NOPS (arg);
 
-  if (TREE_CODE (arg) == ADDR_EXPR
-      && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST)
-    {
-      *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)
+  if (TREE_CODE (arg) == ADDR_EXPR)
     {
-      *ptr_offset = convert (sizetype, TREE_OPERAND (TREE_OPERAND (arg, 0), 1));
-      return TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
+      if (TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST)
+       {
+         *ptr_offset = size_zero_node;
+         return TREE_OPERAND (arg, 0);
+       }
+      else if (TREE_CODE (TREE_OPERAND (arg, 0)) == VAR_DECL)
+       {
+         array = TREE_OPERAND (arg, 0);
+         offset = size_zero_node;
+       }
+      else if (TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF)
+       {
+         array = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
+         offset = TREE_OPERAND (TREE_OPERAND (arg, 0), 1);
+         if (TREE_CODE (array) != STRING_CST
+             && TREE_CODE (array) != VAR_DECL)
+           return 0;
+       }
+      else
+       return 0;
     }
   else if (TREE_CODE (arg) == PLUS_EXPR)
     {
@@ -9466,223 +8328,65 @@ string_constant (tree arg, tree *ptr_offset)
       STRIP_NOPS (arg1);
 
       if (TREE_CODE (arg0) == ADDR_EXPR
-         && TREE_CODE (TREE_OPERAND (arg0, 0)) == STRING_CST)
+         && (TREE_CODE (TREE_OPERAND (arg0, 0)) == STRING_CST
+             || TREE_CODE (TREE_OPERAND (arg0, 0)) == VAR_DECL))
        {
-         *ptr_offset = convert (sizetype, arg1);
-         return TREE_OPERAND (arg0, 0);
+         array = TREE_OPERAND (arg0, 0);
+         offset = arg1;
        }
       else if (TREE_CODE (arg1) == ADDR_EXPR
-              && TREE_CODE (TREE_OPERAND (arg1, 0)) == STRING_CST)
+              && (TREE_CODE (TREE_OPERAND (arg1, 0)) == STRING_CST
+                  || TREE_CODE (TREE_OPERAND (arg1, 0)) == VAR_DECL))
        {
-         *ptr_offset = convert (sizetype, arg0);
-         return TREE_OPERAND (arg1, 0);
+         array = TREE_OPERAND (arg1, 0);
+         offset = arg0;
        }
-    }
-
-  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;
+       return 0;
     }
-  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 || REG_P (op0))
-                && 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);
-       }
+  else
+    return 0;
 
-      temp = expand_assignment (incremented, newexp, ! post && ! ignore);
-      return post ? op0 : temp;
+  if (TREE_CODE (array) == STRING_CST)
+    {
+      *ptr_offset = convert (sizetype, offset);
+      return array;
     }
-
-  if (post)
+  else if (TREE_CODE (array) == VAR_DECL)
     {
-      /* We have a true reference to the value in OP0.
-        If there is an insn to add or subtract in this mode, queue it.
-        Queuing the increment insn avoids the register shuffling
-        that often results if we must increment now and first save
-        the old value for subsequent use.  */
-
-#if 0  /* Turned off to avoid making extra insn for indexed memref.  */
-      op0 = stabilize (op0);
-#endif
+      int length;
 
-      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);
+      /* Variables initialized to string literals can be handled too.  */
+      if (DECL_INITIAL (array) == NULL_TREE
+         || TREE_CODE (DECL_INITIAL (array)) != STRING_CST)
+       return 0;
 
-         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;
-       }
-    }
+      /* If they are read-only, non-volatile and bind locally.  */
+      if (! TREE_READONLY (array)
+         || TREE_SIDE_EFFECTS (array)
+         || ! targetm.binds_local_p (array))
+       return 0;
 
-  /* 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);
+      /* Avoid const char foo[4] = "abcde";  */
+      if (DECL_SIZE_UNIT (array) == NULL_TREE
+         || TREE_CODE (DECL_SIZE_UNIT (array)) != INTEGER_CST
+         || (length = TREE_STRING_LENGTH (DECL_INITIAL (array))) <= 0
+         || compare_tree_int (DECL_SIZE_UNIT (array), length) < 0)
+       return 0;
 
-  /* Increment however we can.  */
-  op1 = expand_binop (mode, this_optab, value, op1, op0,
-                     TYPE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
+      /* If variable is bigger than the string literal, OFFSET must be constant
+        and inside of the bounds of the string literal.  */
+      offset = convert (sizetype, offset);
+      if (compare_tree_int (DECL_SIZE_UNIT (array), length) > 0
+         && (! host_integerp (offset, 1)
+             || compare_tree_int (offset, length) >= 0))
+       return 0;
 
-  /* Make sure the value is stored into OP0.  */
-  if (op1 != op0)
-    emit_move_insn (op0, op1);
+      *ptr_offset = offset;
+      return DECL_INITIAL (array);
+    }
 
-  return temp;
+  return 0;
 }
 \f
 /* Generate code to calculate EXP using a store-flag instruction
@@ -9825,7 +8529,7 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   /* Put a constant second.  */
@@ -9888,13 +8592,7 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
   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)
@@ -9927,8 +8625,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);
@@ -9979,8 +8676,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,
@@ -9999,8 +8696,7 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
 
       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;
@@ -10100,9 +8796,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));
@@ -10122,12 +8816,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),
@@ -10156,7 +8848,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);
@@ -10166,7 +8858,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.  */
@@ -10206,94 +8898,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);
-}
-\f
-/* Called to move the SAVE_EXPRs for parameter declarations in a
-   nested function into the nested function.  DATA is really the
-   nested FUNCTION_DECL.  */
-
-static tree
-set_save_expr_context (tree *tp,
-                       int *walk_subtrees,
-                       void *data)
-{
-  if (TREE_CODE (*tp) == SAVE_EXPR && !SAVE_EXPR_CONTEXT (*tp))
-    SAVE_EXPR_CONTEXT (*tp) = (tree) data;
-  /* Do not walk back into the SAVE_EXPR_CONTEXT; that will cause
-     circularity.  */
-  else if (DECL_P (*tp))
-    *walk_subtrees = 0;
-
-  return NULL;
-}
-
-
-static void
-execute_expand (void)
-{
-  /* If the function has a variably modified type, there may be
-     SAVE_EXPRs in the parameter types.  Their context must be set to
-     refer to this function; they cannot be expanded in the containing
-     function.  */
-  if (decl_function_context (current_function_decl) == current_function_decl
-      && variably_modified_type_p (TREE_TYPE (current_function_decl)))
-    walk_tree (&TREE_TYPE (current_function_decl), set_save_expr_context,
-              current_function_decl, NULL);
-
-  /* Expand the variables recorded during gimple lowering.  This must
-     occur before the call to expand_function_start to ensure that
-     all used variables are expanded before we expand anything on the
-     PENDING_SIZES list.  */
-  expand_used_vars ();
-
-  /* Set up parameters and prepare for return, for the function.  */
-  expand_function_start (current_function_decl, 0);
-
-  /* If this function is `main', emit a call to `__main'
-     to run global initializers, etc.  */
-  if (DECL_NAME (current_function_decl)
-      && MAIN_NAME_P (DECL_NAME (current_function_decl))
-      && DECL_FILE_SCOPE_P (current_function_decl))
-    expand_main_function ();
-
-  /* Generate the RTL for this function.  */
-  expand_expr_stmt_value (DECL_SAVED_TREE (current_function_decl), 0, 0);
-
-  /* We hard-wired immediate_size_expand to zero above.
-     expand_function_end will decrement this variable.  So, we set the
-     variable to one here, so that after the decrement it will remain
-     zero.  */
-  immediate_size_expand = 1;
-
-  /* Make sure the locus is set to the end of the function, so that
-     epilogue line numbers and warnings are set properly.  */
-  if (cfun->function_end_locus.file)
-    input_location = cfun->function_end_locus;
-
-  /* The following insns belong to the top scope.  */
-  record_block_change (DECL_INITIAL (current_function_decl));
-
-  /* Generate rtl for function exit.  */
-  expand_function_end ();
+  return gen_rtx_CONST_VECTOR (mode, v);
 }
-
-struct tree_opt_pass pass_expand =
-{
-  "expand",                            /* name */
-  NULL,                                 /* gate */
-  execute_expand,                      /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_EXPAND,                           /* tv_id */
-  /* ??? If TER is enabled, we actually receive GENERIC.  */
-  PROP_gimple_leh,                      /* properties_required */
-  PROP_rtl,                             /* properties_provided */
-  PROP_cfg | PROP_gimple_leh,           /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  0                                     /* todo_flags_finish */
-};
-
-
 #include "gt-expr.h"