OSDN Git Service

2004-04-30 Uros Bizjak <uros@kss-loka.si>
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index 489aba4..0c40ded 100644 (file)
@@ -1,6 +1,6 @@
 /* Convert tree expression to rtl instructions, for GNU compiler.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -47,6 +47,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "langhooks.h"
 #include "intl.h"
 #include "tm_p.h"
+#include "target.h"
 
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
@@ -72,11 +73,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #endif
 #endif
 
-/* Assume that case vectors are not pc-relative.  */
-#ifndef CASE_VECTOR_PC_RELATIVE
-#define CASE_VECTOR_PC_RELATIVE 0
-#endif
-
 /* Convert defined/undefined to boolean.  */
 #ifdef TARGET_MEM_FUNCTIONS
 #undef TARGET_MEM_FUNCTIONS
@@ -94,9 +90,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    the same indirect address eventually.  */
 int cse_not_expected;
 
-/* Chain of pending expressions for PLACEHOLDER_EXPR to replace.  */
-tree placeholder_list = 0;
-
 /* This structure is used by move_by_pieces to describe the move to
    be performed.  */
 struct move_by_pieces
@@ -160,10 +153,12 @@ static rtx store_field (rtx, HOST_WIDE_INT, HOST_WIDE_INT, enum machine_mode,
 static rtx var_rtx (tree);
 
 static unsigned HOST_WIDE_INT highest_pow2_factor (tree);
-static unsigned HOST_WIDE_INT highest_pow2_factor_for_type (tree, tree);
+static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (tree, tree);
 
 static int is_aligning_offset (tree, tree);
 static rtx expand_increment (tree, int, int);
+static void expand_operands (tree, tree, rtx, rtx*, rtx*,
+                            enum expand_modifier);
 static rtx do_store_flag (tree, rtx, enum machine_mode, int);
 #ifdef PUSH_ROUNDING
 static void emit_single_push_insn (enum machine_mode, rtx, tree);
@@ -182,18 +177,6 @@ static char direct_store[NUM_MACHINE_MODES];
 
 static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
 
-/* If a memory-to-memory move would take MOVE_RATIO or more simple
-   move-instruction sequences, we will do a movstr or libcall instead.  */
-
-#ifndef MOVE_RATIO
-#if defined (HAVE_movstrqi) || defined (HAVE_movstrhi) || defined (HAVE_movstrsi) || defined (HAVE_movstrdi) || defined (HAVE_movstrti)
-#define MOVE_RATIO 2
-#else
-/* If we are optimizing for space (-Os), cut down the default move ratio.  */
-#define MOVE_RATIO (optimize_size ? 3 : 15)
-#endif
-#endif
-
 /* This macro is used to determine whether move_by_pieces should be called
    to perform a structure copy.  */
 #ifndef MOVE_BY_PIECES_P
@@ -201,18 +184,6 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
   (move_by_pieces_ninsns (SIZE, ALIGN) < (unsigned int) MOVE_RATIO)
 #endif
 
-/* If a clear memory operation would take CLEAR_RATIO or more simple
-   move-instruction sequences, we will do a clrstr or libcall instead.  */
-
-#ifndef CLEAR_RATIO
-#if defined (HAVE_clrstrqi) || defined (HAVE_clrstrhi) || defined (HAVE_clrstrsi) || defined (HAVE_clrstrdi) || defined (HAVE_clrstrti)
-#define CLEAR_RATIO 2
-#else
-/* If we are optimizing for space, cut down the default clear ratio.  */
-#define CLEAR_RATIO (optimize_size ? 3 : 15)
-#endif
-#endif
-
 /* This macro is used to determine whether clear_by_pieces should be
    called to clear storage.  */
 #ifndef CLEAR_BY_PIECES_P
@@ -233,6 +204,14 @@ enum insn_code movstr_optab[NUM_MACHINE_MODES];
 /* This array records the insn_code of insns to perform block clears.  */
 enum insn_code clrstr_optab[NUM_MACHINE_MODES];
 
+/* These arrays record the insn_code of two different kinds of insns
+   to perform block compares.  */
+enum insn_code cmpstr_optab[NUM_MACHINE_MODES];
+enum insn_code cmpmem_optab[NUM_MACHINE_MODES];
+
+/* Stack of EXPR_WITH_FILE_LOCATION nested expressions.  */
+struct file_stack *expr_wfl_stack;
+
 /* SLOW_UNALIGNED_ACCESS is nonzero if unaligned accesses are very slow.  */
 
 #ifndef SLOW_UNALIGNED_ACCESS
@@ -487,13 +466,30 @@ queued_subexp_p (rtx x)
     }
 }
 
-/* Perform all the pending incrementations.  */
+/* Retrieve a mark on the queue.  */
+  
+static rtx
+mark_queue (void)
+{
+  return pending_chain;
+}
 
-void
-emit_queue (void)
+/* Perform all the pending incrementations that have been enqueued
+   after MARK was retrieved.  If MARK is null, perform all the
+   pending incrementations.  */
+
+static void
+emit_insns_enqueued_after_mark (rtx mark)
 {
   rtx p;
-  while ((p = pending_chain))
+
+  /* The marked incrementation may have been emitted in the meantime
+     through a call to emit_queue.  In this case, the mark is not valid
+     anymore so do nothing.  */
+  if (mark && ! QUEUED_BODY (mark))
+    return;
+
+  while ((p = pending_chain) != mark)
     {
       rtx body = QUEUED_BODY (p);
 
@@ -520,9 +516,18 @@ emit_queue (void)
          break;
        }
 
+      QUEUED_BODY (p) = 0;
       pending_chain = QUEUED_NEXT (p);
     }
 }
+
+/* Perform all the pending incrementations.  */
+
+void
+emit_queue (void)
+{
+  emit_insns_enqueued_after_mark (NULL_RTX);
+}
 \f
 /* Copy data from FROM to TO, where the machine modes are not the same.
    Both modes may be integer, or both may be floating.
@@ -590,248 +595,32 @@ convert_move (rtx to, rtx from, int unsignedp)
       return;
     }
 
-  if (to_real != from_real)
-    abort ();
-
   if (to_real)
     {
       rtx value, insns;
+      convert_optab tab;
 
-      if (GET_MODE_BITSIZE (from_mode) < GET_MODE_BITSIZE (to_mode))
-       {
-         /* Try converting directly if the insn is supported.  */
-         if ((code = can_extend_p (to_mode, from_mode, 0))
-             != CODE_FOR_nothing)
-           {
-             emit_unop_insn (code, to, from, UNKNOWN);
-             return;
-           }
-       }
-
-#ifdef HAVE_trunchfqf2
-      if (HAVE_trunchfqf2 && from_mode == HFmode && to_mode == QFmode)
-       {
-         emit_unop_insn (CODE_FOR_trunchfqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_trunctqfqf2
-      if (HAVE_trunctqfqf2 && from_mode == TQFmode && to_mode == QFmode)
-       {
-         emit_unop_insn (CODE_FOR_trunctqfqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncsfqf2
-      if (HAVE_truncsfqf2 && from_mode == SFmode && to_mode == QFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncsfqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncdfqf2
-      if (HAVE_truncdfqf2 && from_mode == DFmode && to_mode == QFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncdfqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncxfqf2
-      if (HAVE_truncxfqf2 && from_mode == XFmode && to_mode == QFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncxfqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_trunctfqf2
-      if (HAVE_trunctfqf2 && from_mode == TFmode && to_mode == QFmode)
-       {
-         emit_unop_insn (CODE_FOR_trunctfqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-
-#ifdef HAVE_trunctqfhf2
-      if (HAVE_trunctqfhf2 && from_mode == TQFmode && to_mode == HFmode)
-       {
-         emit_unop_insn (CODE_FOR_trunctqfhf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncsfhf2
-      if (HAVE_truncsfhf2 && from_mode == SFmode && to_mode == HFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncsfhf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncdfhf2
-      if (HAVE_truncdfhf2 && from_mode == DFmode && to_mode == HFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncdfhf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncxfhf2
-      if (HAVE_truncxfhf2 && from_mode == XFmode && to_mode == HFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncxfhf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_trunctfhf2
-      if (HAVE_trunctfhf2 && from_mode == TFmode && to_mode == HFmode)
-       {
-         emit_unop_insn (CODE_FOR_trunctfhf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
+      if (GET_MODE_PRECISION (from_mode) < GET_MODE_PRECISION (to_mode))
+       tab = sext_optab;
+      else if (GET_MODE_PRECISION (from_mode) > GET_MODE_PRECISION (to_mode))
+       tab = trunc_optab;
+      else
+       abort ();
 
-#ifdef HAVE_truncsftqf2
-      if (HAVE_truncsftqf2 && from_mode == SFmode && to_mode == TQFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncsftqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncdftqf2
-      if (HAVE_truncdftqf2 && from_mode == DFmode && to_mode == TQFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncdftqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncxftqf2
-      if (HAVE_truncxftqf2 && from_mode == XFmode && to_mode == TQFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncxftqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_trunctftqf2
-      if (HAVE_trunctftqf2 && from_mode == TFmode && to_mode == TQFmode)
-       {
-         emit_unop_insn (CODE_FOR_trunctftqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
+      /* Try converting directly if the insn is supported.  */
 
-#ifdef HAVE_truncdfsf2
-      if (HAVE_truncdfsf2 && from_mode == DFmode && to_mode == SFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncdfsf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncxfsf2
-      if (HAVE_truncxfsf2 && from_mode == XFmode && to_mode == SFmode)
+      code = tab->handlers[to_mode][from_mode].insn_code;
+      if (code != CODE_FOR_nothing)
        {
-         emit_unop_insn (CODE_FOR_truncxfsf2, to, from, UNKNOWN);
+         emit_unop_insn (code, to, from,
+                         tab == sext_optab ? FLOAT_EXTEND : FLOAT_TRUNCATE);
          return;
        }
-#endif
-#ifdef HAVE_trunctfsf2
-      if (HAVE_trunctfsf2 && from_mode == TFmode && to_mode == SFmode)
-       {
-         emit_unop_insn (CODE_FOR_trunctfsf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_truncxfdf2
-      if (HAVE_truncxfdf2 && from_mode == XFmode && to_mode == DFmode)
-       {
-         emit_unop_insn (CODE_FOR_truncxfdf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_trunctfdf2
-      if (HAVE_trunctfdf2 && from_mode == TFmode && to_mode == DFmode)
-       {
-         emit_unop_insn (CODE_FOR_trunctfdf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
 
-      libcall = (rtx) 0;
-      switch (from_mode)
-       {
-       case SFmode:
-         switch (to_mode)
-           {
-           case DFmode:
-             libcall = extendsfdf2_libfunc;
-             break;
-
-           case XFmode:
-             libcall = extendsfxf2_libfunc;
-             break;
-
-           case TFmode:
-             libcall = extendsftf2_libfunc;
-             break;
-
-           default:
-             break;
-           }
-         break;
-
-       case DFmode:
-         switch (to_mode)
-           {
-           case SFmode:
-             libcall = truncdfsf2_libfunc;
-             break;
-
-           case XFmode:
-             libcall = extenddfxf2_libfunc;
-             break;
-
-           case TFmode:
-             libcall = extenddftf2_libfunc;
-             break;
-
-           default:
-             break;
-           }
-         break;
-
-       case XFmode:
-         switch (to_mode)
-           {
-           case SFmode:
-             libcall = truncxfsf2_libfunc;
-             break;
-
-           case DFmode:
-             libcall = truncxfdf2_libfunc;
-             break;
-
-           default:
-             break;
-           }
-         break;
-
-       case TFmode:
-         switch (to_mode)
-           {
-           case SFmode:
-             libcall = trunctfsf2_libfunc;
-             break;
-
-           case DFmode:
-             libcall = trunctfdf2_libfunc;
-             break;
-
-           default:
-             break;
-           }
-         break;
-
-       default:
-         break;
-       }
+      /* Otherwise use a libcall.  */
+      libcall = tab->handlers[to_mode][from_mode].libfunc;
 
-      if (libcall == (rtx) 0)
+      if (!libcall)
        /* This conversion is not implemented yet.  */
        abort ();
 
@@ -840,11 +629,49 @@ convert_move (rtx to, rtx from, int unsignedp)
                                       1, from, from_mode);
       insns = get_insns ();
       end_sequence ();
-      emit_libcall_block (insns, to, value, gen_rtx_FLOAT_TRUNCATE (to_mode,
-                                                                   from));
+      emit_libcall_block (insns, to, value,
+                         tab == trunc_optab ? gen_rtx_FLOAT_TRUNCATE (to_mode,
+                                                                      from)
+                         : gen_rtx_FLOAT_EXTEND (to_mode, from));
       return;
     }
 
+  /* Handle pointer conversion.  */                    /* SPEE 900220.  */
+  /* Targets are expected to provide conversion insns between PxImode and
+     xImode for all MODE_PARTIAL_INT modes they use, but no others.  */
+  if (GET_MODE_CLASS (to_mode) == MODE_PARTIAL_INT)
+    {
+      enum machine_mode full_mode
+       = smallest_mode_for_size (GET_MODE_BITSIZE (to_mode), MODE_INT);
+
+      if (trunc_optab->handlers[to_mode][full_mode].insn_code
+         == CODE_FOR_nothing)
+       abort ();
+
+      if (full_mode != from_mode)
+       from = convert_to_mode (full_mode, from, unsignedp);
+      emit_unop_insn (trunc_optab->handlers[to_mode][full_mode].insn_code,
+                     to, from, UNKNOWN);
+      return;
+    }
+  if (GET_MODE_CLASS (from_mode) == MODE_PARTIAL_INT)
+    {
+      enum machine_mode full_mode
+       = smallest_mode_for_size (GET_MODE_BITSIZE (from_mode), MODE_INT);
+
+      if (sext_optab->handlers[full_mode][from_mode].insn_code
+         == CODE_FOR_nothing)
+       abort ();
+
+      emit_unop_insn (sext_optab->handlers[full_mode][from_mode].insn_code,
+                     to, from, UNKNOWN);
+      if (to_mode == full_mode)
+       return;
+
+      /* else proceed to integer conversions below.  */
+      from_mode = full_mode;
+    }
+
   /* Now both modes are integers.  */
 
   /* Handle expanding beyond a word.  */
@@ -878,7 +705,11 @@ convert_move (rtx to, rtx from, int unsignedp)
                   != CODE_FOR_nothing))
        {
          if (GET_CODE (to) == REG)
-           emit_insn (gen_rtx_CLOBBER (VOIDmode, to));
+           {
+             if (reg_overlap_mentioned_p (to, from))
+               from = force_reg (from_mode, from);
+             emit_insn (gen_rtx_CLOBBER (VOIDmode, to));
+           }
          convert_move (gen_lowpart (word_mode, to), from, unsignedp);
          emit_unop_insn (code, to,
                          gen_lowpart (word_mode, to), equiv_code);
@@ -967,119 +798,6 @@ convert_move (rtx to, rtx from, int unsignedp)
       return;
     }
 
-  /* Handle pointer conversion.  */                    /* SPEE 900220.  */
-  if (to_mode == PQImode)
-    {
-      if (from_mode != QImode)
-       from = convert_to_mode (QImode, from, unsignedp);
-
-#ifdef HAVE_truncqipqi2
-      if (HAVE_truncqipqi2)
-       {
-         emit_unop_insn (CODE_FOR_truncqipqi2, to, from, UNKNOWN);
-         return;
-       }
-#endif /* HAVE_truncqipqi2 */
-      abort ();
-    }
-
-  if (from_mode == PQImode)
-    {
-      if (to_mode != QImode)
-       {
-         from = convert_to_mode (QImode, from, unsignedp);
-         from_mode = QImode;
-       }
-      else
-       {
-#ifdef HAVE_extendpqiqi2
-         if (HAVE_extendpqiqi2)
-           {
-             emit_unop_insn (CODE_FOR_extendpqiqi2, to, from, UNKNOWN);
-             return;
-           }
-#endif /* HAVE_extendpqiqi2 */
-         abort ();
-       }
-    }
-
-  if (to_mode == PSImode)
-    {
-      if (from_mode != SImode)
-       from = convert_to_mode (SImode, from, unsignedp);
-
-#ifdef HAVE_truncsipsi2
-      if (HAVE_truncsipsi2)
-       {
-         emit_unop_insn (CODE_FOR_truncsipsi2, to, from, UNKNOWN);
-         return;
-       }
-#endif /* HAVE_truncsipsi2 */
-      abort ();
-    }
-
-  if (from_mode == PSImode)
-    {
-      if (to_mode != SImode)
-       {
-         from = convert_to_mode (SImode, from, unsignedp);
-         from_mode = SImode;
-       }
-      else
-       {
-#ifdef HAVE_extendpsisi2
-         if (! unsignedp && HAVE_extendpsisi2)
-           {
-             emit_unop_insn (CODE_FOR_extendpsisi2, to, from, UNKNOWN);
-             return;
-           }
-#endif /* HAVE_extendpsisi2 */
-#ifdef HAVE_zero_extendpsisi2
-         if (unsignedp && HAVE_zero_extendpsisi2)
-           {
-             emit_unop_insn (CODE_FOR_zero_extendpsisi2, to, from, UNKNOWN);
-             return;
-           }
-#endif /* HAVE_zero_extendpsisi2 */
-         abort ();
-       }
-    }
-
-  if (to_mode == PDImode)
-    {
-      if (from_mode != DImode)
-       from = convert_to_mode (DImode, from, unsignedp);
-
-#ifdef HAVE_truncdipdi2
-      if (HAVE_truncdipdi2)
-       {
-         emit_unop_insn (CODE_FOR_truncdipdi2, to, from, UNKNOWN);
-         return;
-       }
-#endif /* HAVE_truncdipdi2 */
-      abort ();
-    }
-
-  if (from_mode == PDImode)
-    {
-      if (to_mode != DImode)
-       {
-         from = convert_to_mode (DImode, from, unsignedp);
-         from_mode = DImode;
-       }
-      else
-       {
-#ifdef HAVE_extendpdidi2
-         if (HAVE_extendpdidi2)
-           {
-             emit_unop_insn (CODE_FOR_extendpdidi2, to, from, UNKNOWN);
-             return;
-           }
-#endif /* HAVE_extendpdidi2 */
-         abort ();
-       }
-    }
-
   /* Now follow all the conversions between integers
      no more than a word long.  */
 
@@ -1128,165 +846,45 @@ convert_move (rtx to, rtx from, int unsignedp)
                  != CODE_FOR_nothing)
                 || (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (intermediate)
                     && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (to_mode),
-                                              GET_MODE_BITSIZE (intermediate))))
-               && (can_extend_p (intermediate, from_mode, unsignedp)
-                   != CODE_FOR_nothing))
-             {
-               convert_move (to, convert_to_mode (intermediate, from,
-                                                  unsignedp), unsignedp);
-               return;
-             }
-
-         /* No suitable intermediate mode.
-            Generate what we need with shifts.  */
-         shift_amount = build_int_2 (GET_MODE_BITSIZE (to_mode)
-                                     - GET_MODE_BITSIZE (from_mode), 0);
-         from = gen_lowpart (to_mode, force_reg (from_mode, from));
-         tmp = expand_shift (LSHIFT_EXPR, to_mode, from, shift_amount,
-                             to, unsignedp);
-         tmp = expand_shift (RSHIFT_EXPR, to_mode, tmp, shift_amount,
-                             to, unsignedp);
-         if (tmp != to)
-           emit_move_insn (to, tmp);
-         return;
-       }
-    }
-
-  /* Support special truncate insns for certain modes.  */
-
-  if (from_mode == DImode && to_mode == SImode)
-    {
-#ifdef HAVE_truncdisi2
-      if (HAVE_truncdisi2)
-       {
-         emit_unop_insn (CODE_FOR_truncdisi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
-
-  if (from_mode == DImode && to_mode == HImode)
-    {
-#ifdef HAVE_truncdihi2
-      if (HAVE_truncdihi2)
-       {
-         emit_unop_insn (CODE_FOR_truncdihi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
-
-  if (from_mode == DImode && to_mode == QImode)
-    {
-#ifdef HAVE_truncdiqi2
-      if (HAVE_truncdiqi2)
-       {
-         emit_unop_insn (CODE_FOR_truncdiqi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
-
-  if (from_mode == SImode && to_mode == HImode)
-    {
-#ifdef HAVE_truncsihi2
-      if (HAVE_truncsihi2)
-       {
-         emit_unop_insn (CODE_FOR_truncsihi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
-
-  if (from_mode == SImode && to_mode == QImode)
-    {
-#ifdef HAVE_truncsiqi2
-      if (HAVE_truncsiqi2)
-       {
-         emit_unop_insn (CODE_FOR_truncsiqi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
-
-  if (from_mode == HImode && to_mode == QImode)
-    {
-#ifdef HAVE_trunchiqi2
-      if (HAVE_trunchiqi2)
-       {
-         emit_unop_insn (CODE_FOR_trunchiqi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
-
-  if (from_mode == TImode && to_mode == DImode)
-    {
-#ifdef HAVE_trunctidi2
-      if (HAVE_trunctidi2)
-       {
-         emit_unop_insn (CODE_FOR_trunctidi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
-
-  if (from_mode == TImode && to_mode == SImode)
-    {
-#ifdef HAVE_trunctisi2
-      if (HAVE_trunctisi2)
-       {
-         emit_unop_insn (CODE_FOR_trunctisi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
-    }
+                                              GET_MODE_BITSIZE (intermediate))))
+               && (can_extend_p (intermediate, from_mode, unsignedp)
+                   != CODE_FOR_nothing))
+             {
+               convert_move (to, convert_to_mode (intermediate, from,
+                                                  unsignedp), unsignedp);
+               return;
+             }
 
-  if (from_mode == TImode && to_mode == HImode)
-    {
-#ifdef HAVE_trunctihi2
-      if (HAVE_trunctihi2)
-       {
-         emit_unop_insn (CODE_FOR_trunctihi2, to, from, UNKNOWN);
+         /* No suitable intermediate mode.
+            Generate what we need with shifts.  */
+         shift_amount = build_int_2 (GET_MODE_BITSIZE (to_mode)
+                                     - GET_MODE_BITSIZE (from_mode), 0);
+         from = gen_lowpart (to_mode, force_reg (from_mode, from));
+         tmp = expand_shift (LSHIFT_EXPR, to_mode, from, shift_amount,
+                             to, unsignedp);
+         tmp = expand_shift (RSHIFT_EXPR, to_mode, tmp, shift_amount,
+                             to, unsignedp);
+         if (tmp != to)
+           emit_move_insn (to, tmp);
          return;
        }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
-      return;
     }
 
-  if (from_mode == TImode && to_mode == QImode)
+  /* Support special truncate insns for certain modes.  */
+  if (trunc_optab->handlers[to_mode][from_mode].insn_code != CODE_FOR_nothing)
     {
-#ifdef HAVE_trunctiqi2
-      if (HAVE_trunctiqi2)
-       {
-         emit_unop_insn (CODE_FOR_trunctiqi2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-      convert_move (to, force_reg (from_mode, from), unsignedp);
+      emit_unop_insn (trunc_optab->handlers[to_mode][from_mode].insn_code,
+                     to, from, UNKNOWN);
       return;
     }
 
   /* Handle truncation of volatile memrefs, and so on;
      the things that couldn't be truncated directly,
-     and for which there was no special instruction.  */
+     and for which there was no special instruction.
+
+     ??? Code above formerly short-circuited this, for most integer
+     mode pairs, with a force_reg in from_mode followed by a recursive
+     call to this routine.  Appears always to have been wrong.  */
   if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode))
     {
       rtx temp = force_reg (to_mode, gen_lowpart (to_mode, from));
@@ -1797,56 +1395,46 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
 static bool
 block_move_libcall_safe_for_call_parm (void)
 {
+  /* If arguments are pushed on the stack, then they're safe.  */
   if (PUSH_ARGS)
     return true;
-  else
-    {
-      /* Check to see whether memcpy takes all register arguments.  */
-      static enum {
-       takes_regs_uninit, takes_regs_no, takes_regs_yes
-      } takes_regs = takes_regs_uninit;
-
-      switch (takes_regs)
-       {
-       case takes_regs_uninit:
-         {
-           CUMULATIVE_ARGS args_so_far;
-           tree fn, arg;
 
-           fn = emit_block_move_libcall_fn (false);
-           INIT_CUMULATIVE_ARGS (args_so_far, TREE_TYPE (fn), NULL_RTX, 0);
-
-           arg = TYPE_ARG_TYPES (TREE_TYPE (fn));
-           for ( ; arg != void_list_node ; arg = TREE_CHAIN (arg))
-             {
-               enum machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
-               rtx tmp = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
-               if (!tmp || !REG_P (tmp))
-                 goto fail_takes_regs;
-#ifdef FUNCTION_ARG_PARTIAL_NREGS
-               if (FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode,
-                                               NULL_TREE, 1))
-                 goto fail_takes_regs;
+  /* If registers go on the stack anyway, any argument is sure to clobber
+     an outgoing argument.  */
+#if defined (REG_PARM_STACK_SPACE) && defined (OUTGOING_REG_PARM_STACK_SPACE)
+  {
+    tree fn = emit_block_move_libcall_fn (false);
+    (void) fn;
+    if (REG_PARM_STACK_SPACE (fn) != 0)
+      return false;
+  }
 #endif
-               FUNCTION_ARG_ADVANCE (args_so_far, mode, NULL_TREE, 1);
-             }
-         }
-         takes_regs = takes_regs_yes;
-         /* FALLTHRU */
 
-       case takes_regs_yes:
-         return true;
+  /* If any argument goes in memory, then it might clobber an outgoing
+     argument.  */
+  {
+    CUMULATIVE_ARGS args_so_far;
+    tree fn, arg;
 
-       fail_takes_regs:
-         takes_regs = takes_regs_no;
-         /* FALLTHRU */
-       case takes_regs_no:
-         return false;
+    fn = emit_block_move_libcall_fn (false);
+    INIT_CUMULATIVE_ARGS (args_so_far, TREE_TYPE (fn), NULL_RTX, 0, 3);
 
-       default:
-         abort ();
-       }
-    }
+    arg = TYPE_ARG_TYPES (TREE_TYPE (fn));
+    for ( ; arg != void_list_node ; arg = TREE_CHAIN (arg))
+      {
+       enum machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
+       rtx tmp = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
+       if (!tmp || !REG_P (tmp))
+         return false;
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+       if (FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode,
+                                       NULL_TREE, 1))
+         return false;
+#endif
+       FUNCTION_ARG_ADVANCE (args_so_far, mode, NULL_TREE, 1);
+      }
+  }
+  return true;
 }
 
 /* A subroutine of emit_block_move.  Expand a movstr pattern;
@@ -1856,6 +1444,7 @@ static bool
 emit_block_move_via_movstr (rtx x, rtx y, rtx size, unsigned int align)
 {
   rtx opalign = GEN_INT (align / BITS_PER_UNIT);
+  int save_volatile_ok = volatile_ok;
   enum machine_mode mode;
 
   /* Since this is a move insn, we don't care about volatility.  */
@@ -1905,7 +1494,7 @@ emit_block_move_via_movstr (rtx x, rtx y, rtx size, unsigned int align)
          if (pat)
            {
              emit_insn (pat);
-             volatile_ok = 0;
+             volatile_ok = save_volatile_ok;
              return true;
            }
          else
@@ -1913,7 +1502,7 @@ emit_block_move_via_movstr (rtx x, rtx y, rtx size, unsigned int align)
        }
     }
 
-  volatile_ok = 0;
+  volatile_ok = save_volatile_ok;
   return false;
 }
 
@@ -1952,10 +1541,8 @@ emit_block_move_via_libcall (rtx dst, rtx src, rtx size)
   dst_addr = copy_to_mode_reg (Pmode, XEXP (dst, 0));
   src_addr = copy_to_mode_reg (Pmode, XEXP (src, 0));
 
-#ifdef POINTERS_EXTEND_UNSIGNED
   dst_addr = convert_memory_address (ptr_mode, dst_addr);
   src_addr = convert_memory_address (ptr_mode, src_addr);
-#endif
 
   dst_tree = make_tree (ptr_type_node, dst_addr);
   src_tree = make_tree (ptr_type_node, src_addr);
@@ -2245,7 +1832,7 @@ gen_group_rtx (rtx orig)
 /* Emit code to move a block ORIG_SRC of type TYPE to a block DST,
    where DST is non-consecutive registers represented by a PARALLEL.
    SSIZE represents the total size of block ORIG_SRC in bytes, or -1
-   if not known.  */ 
+   if not known.  */
 
 void
 emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
@@ -2360,6 +1947,9 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
          emit_move_insn (mem, src);
          tmps[i] = adjust_address (mem, mode, (int) bytepos);
        }
+      else if (CONSTANT_P (src) && GET_MODE (dst) != BLKmode
+               && XVECLEN (dst, 0) > 1)
+        tmps[i] = simplify_gen_subreg (mode, src, GET_MODE(dst), bytepos);
       else if (CONSTANT_P (src)
               || (GET_CODE (src) == REG && GET_MODE (src) == mode))
        tmps[i] = src;
@@ -2534,10 +2124,10 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
    set of registers starting with SRCREG into TGTBLK.  If TGTBLK
    is null, a stack temporary is created.  TGTBLK is returned.
 
-   The primary purpose of this routine is to handle functions
-   that return BLKmode structures in registers.  Some machines
-   (the PA for example) want to return all small structures
-   in registers regardless of the structure's alignment.  */
+   The purpose of this routine is to handle functions that return
+   BLKmode structures in registers.  Some machines (the PA for example)
+   want to return all small structures in registers regardless of the
+   structure's alignment.  */
 
 rtx
 copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
@@ -2545,7 +2135,7 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
   unsigned HOST_WIDE_INT bytes = int_size_in_bytes (type);
   rtx src = NULL, dst = NULL;
   unsigned HOST_WIDE_INT bitsize = MIN (TYPE_ALIGN (type), BITS_PER_WORD);
-  unsigned HOST_WIDE_INT bitpos, xbitpos, big_endian_correction = 0;
+  unsigned HOST_WIDE_INT bitpos, xbitpos, padding_correction = 0;
 
   if (tgtblk == 0)
     {
@@ -2561,15 +2151,22 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
 
   if (GET_MODE (srcreg) != BLKmode
       && GET_MODE_SIZE (GET_MODE (srcreg)) < UNITS_PER_WORD)
-    srcreg = convert_to_mode (word_mode, srcreg, TREE_UNSIGNED (type));
-
-  /* Structures whose size is not a multiple of a word are aligned
-     to the least significant byte (to the right).  On a BYTES_BIG_ENDIAN
-     machine, this means we must skip the empty high order bytes when
-     calculating the bit offset.  */
-  if (BYTES_BIG_ENDIAN
-      && bytes % UNITS_PER_WORD)
-    big_endian_correction
+    srcreg = convert_to_mode (word_mode, srcreg, TYPE_UNSIGNED (type));
+
+  /* If the structure doesn't take up a whole number of words, see whether
+     SRCREG is padded on the left or on the right.  If it's on the left,
+     set PADDING_CORRECTION to the number of bits to skip.
+
+     In most ABIs, the structure will be returned at the least end of
+     the register, which translates to right padding on little-endian
+     targets and left padding on big-endian targets.  The opposite
+     holds if the structure is returned at the most significant
+     end of the register.  */
+  if (bytes % UNITS_PER_WORD != 0
+      && (targetm.calls.return_in_msb (type)
+         ? !BYTES_BIG_ENDIAN
+         : BYTES_BIG_ENDIAN))
+    padding_correction
       = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) * BITS_PER_UNIT));
 
   /* Copy the structure BITSIZE bites at a time.
@@ -2577,15 +2174,15 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
      We could probably emit more efficient code for machines which do not use
      strict alignment, but it doesn't seem worth the effort at the current
      time.  */
-  for (bitpos = 0, xbitpos = big_endian_correction;
+  for (bitpos = 0, xbitpos = padding_correction;
        bitpos < bytes * BITS_PER_UNIT;
        bitpos += bitsize, xbitpos += bitsize)
     {
       /* We need a new source operand each time xbitpos is on a
-        word boundary and when xbitpos == big_endian_correction
+        word boundary and when xbitpos == padding_correction
         (the first time through).  */
       if (xbitpos % BITS_PER_WORD == 0
-         || xbitpos == big_endian_correction)
+         || xbitpos == padding_correction)
        src = operand_subword_force (srcreg, xbitpos / BITS_PER_WORD,
                                     GET_MODE (srcreg));
 
@@ -3488,6 +3085,17 @@ emit_move_insn_1 (rtx x, rtx y)
       return emit_insn (GEN_FCN (insn_code) (x, y));
     }
 
+  /* Try using a move pattern for the corresponding integer mode.  This is
+     only safe when simplify_subreg can convert MODE constants into integer
+     constants.  At present, it can only do this reliably if the value
+     fits within a HOST_WIDE_INT.  */
+  else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+          && (submode = int_mode_for_mode (mode)) != BLKmode
+          && mov_optab->handlers[submode].insn_code != CODE_FOR_nothing)
+    return emit_insn (GEN_FCN (mov_optab->handlers[submode].insn_code)
+                     (simplify_gen_subreg (submode, x, mode, 0),
+                      simplify_gen_subreg (submode, y, mode, 0)));
+
   /* This will handle any multi-word or full-word mode that lacks a move_insn
      pattern.  However, you will get better code if you define such patterns,
      even if they must turn into multiple assembler instructions.  */
@@ -3868,9 +3476,19 @@ emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
 
       rtx temp;
       int used = partial * UNITS_PER_WORD;
-      int offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
+      int offset;
       int skip;
 
+      if (reg && GET_CODE (reg) == PARALLEL)
+       {
+         /* Use the size of the elt to compute offset.  */
+         rtx elt = XEXP (XVECEXP (reg, 0, 0), 0);
+         used = partial * GET_MODE_SIZE (GET_MODE (elt));
+         offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
+       }
+      else
+       offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
+
       if (size == 0)
        abort ();
 
@@ -4205,8 +3823,8 @@ expand_assignment (tree to, tree from, int want_value)
            }
 
          to_rtx = offset_address (to_rtx, offset_rtx,
-                                  highest_pow2_factor_for_type (TREE_TYPE (to),
-                                                                offset));
+                                  highest_pow2_factor_for_target (to,
+                                                                  offset));
        }
 
       if (GET_CODE (to_rtx) == MEM)
@@ -4228,7 +3846,11 @@ expand_assignment (tree to, tree from, int want_value)
        }
 
       if (TREE_CODE (to) == COMPONENT_REF
-         && TREE_READONLY (TREE_OPERAND (to, 1)))
+         && TREE_READONLY (TREE_OPERAND (to, 1))
+         /* We can't assert that a MEM won't be set more than once
+            if the component is not addressable because another
+            non-addressable component may be referenced by the same MEM.  */
+         && ! (GET_CODE (to_rtx) == MEM && ! can_address_p (to)))
        {
          if (to_rtx == orig_to_rtx)
            to_rtx = copy_rtx (to_rtx);
@@ -4259,7 +3881,7 @@ expand_assignment (tree to, tree from, int want_value)
       return (want_value ? convert_modes (TYPE_MODE (TREE_TYPE (to)),
                                          TYPE_MODE (TREE_TYPE (from)),
                                          result,
-                                         TREE_UNSIGNED (TREE_TYPE (to)))
+                                         TYPE_UNSIGNED (TREE_TYPE (to)))
              : NULL_RTX);
     }
 
@@ -4273,7 +3895,7 @@ expand_assignment (tree to, tree from, int want_value)
      since it might be a promoted variable where the zero- or sign- extension
      needs to be done.  Handling this in the normal way is safe because no
      computation is done before the call.  */
-  if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from)
+  if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from, from)
       && TREE_CODE (TYPE_SIZE (TREE_TYPE (from))) == INTEGER_CST
       && ! ((TREE_CODE (to) == VAR_DECL || TREE_CODE (to) == PARM_DECL)
            && GET_CODE (DECL_RTL (to)) == REG))
@@ -4294,11 +3916,8 @@ expand_assignment (tree to, tree from, int want_value)
        emit_block_move (to_rtx, value, expr_size (from), BLOCK_OP_NORMAL);
       else
        {
-#ifdef POINTERS_EXTEND_UNSIGNED
-         if (POINTER_TYPE_P (TREE_TYPE (to))
-             && GET_MODE (to_rtx) != GET_MODE (value))
+         if (POINTER_TYPE_P (TREE_TYPE (to)))
            value = convert_memory_address (GET_MODE (to_rtx), value);
-#endif
          emit_move_insn (to_rtx, value);
        }
       preserve_temp_slots (to_rtx);
@@ -4352,7 +3971,7 @@ expand_assignment (tree to, tree from, int want_value)
                           VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
                           XEXP (from_rtx, 0), Pmode,
                           convert_to_mode (TYPE_MODE (sizetype),
-                                           size, TREE_UNSIGNED (sizetype)),
+                                           size, TYPE_UNSIGNED (sizetype)),
                           TYPE_MODE (sizetype));
       else
         emit_library_call (bcopy_libfunc, LCT_NORMAL,
@@ -4360,7 +3979,7 @@ expand_assignment (tree to, tree from, int want_value)
                           XEXP (to_rtx, 0), Pmode,
                           convert_to_mode (TYPE_MODE (integer_type_node),
                                            size,
-                                           TREE_UNSIGNED (integer_type_node)),
+                                           TYPE_UNSIGNED (integer_type_node)),
                           TYPE_MODE (integer_type_node));
 
       preserve_temp_slots (to_rtx);
@@ -4409,6 +4028,8 @@ rtx
 store_expr (tree exp, rtx target, int want_value)
 {
   rtx temp;
+  rtx alt_rtl = NULL_RTX;
+  rtx mark = mark_queue ();
   int dont_return_target = 0;
   int dont_store_target = 0;
 
@@ -4528,13 +4149,13 @@ store_expr (tree exp, rtx target, int want_value)
          && INTEGRAL_TYPE_P (TREE_TYPE (exp))
          && TREE_TYPE (TREE_TYPE (exp)) == 0)
        {
-         if (TREE_UNSIGNED (TREE_TYPE (exp))
+         if (TYPE_UNSIGNED (TREE_TYPE (exp))
              != SUBREG_PROMOTED_UNSIGNED_P (target))
            exp = convert
-             ((*lang_hooks.types.signed_or_unsigned_type)
+             (lang_hooks.types.signed_or_unsigned_type
               (SUBREG_PROMOTED_UNSIGNED_P (target), TREE_TYPE (exp)), exp);
 
-         exp = convert ((*lang_hooks.types.type_for_mode)
+         exp = convert (lang_hooks.types.type_for_mode
                         (GET_MODE (SUBREG_REG (target)),
                          SUBREG_PROMOTED_UNSIGNED_P (target)),
                         exp);
@@ -4590,8 +4211,10 @@ store_expr (tree exp, rtx target, int want_value)
     }
   else
     {
-      temp = expand_expr (exp, target, GET_MODE (target),
-                         want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
+      temp = expand_expr_real (exp, target, GET_MODE (target),
+                              (want_value & 2 
+                               ? EXPAND_STACK_PARM : EXPAND_NORMAL),
+                              &alt_rtl);
       /* Return TARGET if it's a specified hardware register.
         If TARGET is a volatile mem ref, either return TARGET
         or return a reg copied *from* TARGET; ANSI requires this.
@@ -4615,10 +4238,14 @@ store_expr (tree exp, rtx target, int want_value)
       && TREE_CODE (exp) != ERROR_MARK
       && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
     temp = convert_modes (GET_MODE (target), TYPE_MODE (TREE_TYPE (exp)),
-                         temp, TREE_UNSIGNED (TREE_TYPE (exp)));
+                         temp, TYPE_UNSIGNED (TREE_TYPE (exp)));
 
   /* If value was not generated in the target, store it there.
-     Convert the value to TARGET's type first if necessary.
+     Convert the value to TARGET's type first if necessary and emit the
+     pending incrementations that have been queued when expanding EXP.
+     Note that we cannot emit the whole queue blindly because this will
+     effectively disable the POST_INC optimization later.
+
      If TEMP and TARGET compare equal according to rtx_equal_p, but
      one or both of them are volatile memory refs, we have to distinguish
      two cases:
@@ -4636,22 +4263,23 @@ store_expr (tree exp, rtx target, int want_value)
                              || side_effects_p (target))))
       && TREE_CODE (exp) != ERROR_MARK
       && ! dont_store_target
-        /* If store_expr stores a DECL whose DECL_RTL(exp) == TARGET,
-           but TARGET is not valid memory reference, TEMP will differ
-           from TARGET although it is really the same location.  */
-      && (TREE_CODE_CLASS (TREE_CODE (exp)) != 'd'
-         || target != DECL_RTL_IF_SET (exp))
+      /* If store_expr stores a DECL whose DECL_RTL(exp) == TARGET,
+        but TARGET is not valid memory reference, TEMP will differ
+        from TARGET although it is really the same location.  */
+      && !(alt_rtl && rtx_equal_p (alt_rtl, target))
       /* If there's nothing to copy, don't bother.  Don't call expr_size
         unless necessary, because some front-ends (C++) expr_size-hook
         aborts on objects that are not supposed to be bit-copied or
         bit-initialized.  */
       && expr_size (exp) != const0_rtx)
     {
+      emit_insns_enqueued_after_mark (mark);
       target = protect_from_queue (target, 1);
+      temp = protect_from_queue (temp, 0);
       if (GET_MODE (temp) != GET_MODE (target)
          && GET_MODE (temp) != VOIDmode)
        {
-         int unsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
+         int unsignedp = TYPE_UNSIGNED (TREE_TYPE (exp));
          if (dont_return_target)
            {
              /* In this case, we will return TEMP,
@@ -4692,7 +4320,7 @@ store_expr (tree exp, rtx target, int want_value)
 
              /* Copy that much.  */
              copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx,
-                                              TREE_UNSIGNED (sizetype));
+                                              TYPE_UNSIGNED (sizetype));
              emit_block_move (target, temp, copy_size_rtx,
                               (want_value & 2
                                ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
@@ -4714,7 +4342,7 @@ store_expr (tree exp, rtx target, int want_value)
 #ifdef POINTERS_EXTEND_UNSIGNED
                  if (GET_MODE (copy_size_rtx) != Pmode)
                    copy_size_rtx = convert_to_mode (Pmode, copy_size_rtx,
-                                                    TREE_UNSIGNED (sizetype));
+                                                    TYPE_UNSIGNED (sizetype));
 #endif
 
                  target = offset_address (target, copy_size_rtx,
@@ -4741,7 +4369,11 @@ store_expr (tree exp, rtx target, int want_value)
                         (want_value & 2
                          ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
       else
-       emit_move_insn (target, temp);
+       {
+         temp = force_operand (temp, target);
+         if (temp != target)
+           emit_move_insn (target, temp);
+       }
     }
 
   /* If we don't want a value, return NULL_RTX.  */
@@ -5006,9 +4638,10 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            {
              rtx offset_rtx;
 
-             if (CONTAINS_PLACEHOLDER_P (offset))
-               offset = build (WITH_RECORD_EXPR, sizetype,
-                               offset, make_tree (TREE_TYPE (exp), target));
+             offset
+               = SUBSTITUTE_PLACEHOLDER_IN_EXPR (offset,
+                                                 make_tree (TREE_TYPE (exp),
+                                                            target));
 
              offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
              if (GET_CODE (to_rtx) != MEM)
@@ -5051,8 +4684,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
 
              if (TYPE_PRECISION (type) < BITS_PER_WORD)
                {
-                 type = (*lang_hooks.types.type_for_size)
-                   (BITS_PER_WORD, TREE_UNSIGNED (type));
+                 type = lang_hooks.types.type_for_size
+                   (BITS_PER_WORD, TYPE_UNSIGNED (type));
                  value = convert (type, value);
                }
 
@@ -5088,6 +4721,10 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
       int const_bounds_p;
       HOST_WIDE_INT minelt = 0;
       HOST_WIDE_INT maxelt = 0;
+      int icode = 0;
+      rtx *vector = NULL;
+      int elt_size = 0;
+      unsigned n_elts = 0;
 
       /* Vectors are like arrays, but the domain is stored via an array
         type indirectly.  */
@@ -5098,6 +4735,22 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
             it always will.  */
          domain = TYPE_DEBUG_REPRESENTATION_TYPE (type);
          domain = TYPE_DOMAIN (TREE_TYPE (TYPE_FIELDS (domain)));
+         if (REG_P (target) && VECTOR_MODE_P (GET_MODE (target)))
+           {
+             enum machine_mode mode = GET_MODE (target);
+
+             icode = (int) vec_init_optab->handlers[mode].insn_code;
+             if (icode != CODE_FOR_nothing)
+               {
+                 unsigned int i;
+
+                 elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
+                 n_elts = (GET_MODE_SIZE (mode) / elt_size);
+                 vector = alloca (n_elts);
+                 for (i = 0; i < n_elts; i++)
+                   vector [i] = CONST0_RTX (GET_MODE_INNER (mode));
+               }
+           }
        }
 
       const_bounds_p = (TYPE_MIN_VALUE (domain)
@@ -5162,7 +4815,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            need_to_clear = 1;
        }
 
-      if (need_to_clear && size > 0)
+      if (need_to_clear && size > 0 && !vector)
        {
          if (! cleared)
            {
@@ -5195,7 +4848,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
          if (cleared && is_zeros_p (value))
            continue;
 
-         unsignedp = TREE_UNSIGNED (elttype);
+         unsignedp = TYPE_UNSIGNED (elttype);
          mode = TYPE_MODE (elttype);
          if (mode == BLKmode)
            bitsize = (host_integerp (TYPE_SIZE (elttype), 1)
@@ -5213,6 +4866,9 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
              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)
@@ -5250,7 +4906,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                  expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
                  loop_end = gen_label_rtx ();
 
-                 unsignedp = TREE_UNSIGNED (domain);
+                 unsignedp = TYPE_UNSIGNED (domain);
 
                  index = build_decl (VAR_DECL, NULL_TREE, domain);
 
@@ -5304,6 +4960,9 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            {
              tree position;
 
+             if (vector)
+               abort ();
+
              if (index == 0)
                index = ssize_int (1);
 
@@ -5321,6 +4980,16 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
              xtarget = adjust_address (xtarget, mode, 0);
              store_expr (value, xtarget, 0);
            }
+         else if (vector)
+           {
+             int pos;
+
+             if (index != 0)
+               pos = tree_low_cst (index, 0) - minelt;
+             else
+               pos = i;
+             vector[pos] = expand_expr (value, NULL_RTX, VOIDmode, 0);
+           }
          else
            {
              if (index != 0)
@@ -5336,12 +5005,16 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                  target = copy_rtx (target);
                  MEM_KEEP_ALIAS_SET_P (target) = 1;
                }
-
              store_constructor_field (target, bitsize, bitpos, mode, value,
                                       type, cleared, get_alias_set (elttype));
-
            }
        }
+      if (vector)
+       {
+         emit_insn (GEN_FCN (icode) (target,
+                                     gen_rtx_PARALLEL (GET_MODE (target),
+                                                       gen_rtvec_v (n_elts, vector))));
+       }
     }
 
   /* Set constructor assignments.  */
@@ -5408,7 +5081,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                {
                  if (word != 0 || ! cleared)
                    {
-                     rtx datum = GEN_INT (word);
+                     rtx datum = gen_int_mode (word, mode);
                      rtx to_rtx;
 
                      /* The assumption here is that it is safe to use
@@ -5478,7 +5151,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            {
              targetx
                = assign_temp
-                 ((build_qualified_type ((*lang_hooks.types.type_for_mode)
+                 ((build_qualified_type (lang_hooks.types.type_for_mode
                                          (GET_MODE (target), 0),
                                          TYPE_QUAL_CONST)),
                   0, 1, 1);
@@ -5757,7 +5430,6 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
   enum machine_mode mode = VOIDmode;
   tree offset = size_zero_node;
   tree bit_offset = bitsize_zero_node;
-  tree placeholder_ptr = 0;
   tree tem;
 
   /* First get the mode, signedness, and size.  We do this from just the
@@ -5768,17 +5440,17 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
       if (! DECL_BIT_FIELD (TREE_OPERAND (exp, 1)))
        mode = DECL_MODE (TREE_OPERAND (exp, 1));
 
-      *punsignedp = TREE_UNSIGNED (TREE_OPERAND (exp, 1));
+      *punsignedp = DECL_UNSIGNED (TREE_OPERAND (exp, 1));
     }
   else if (TREE_CODE (exp) == BIT_FIELD_REF)
     {
       size_tree = TREE_OPERAND (exp, 1);
-      *punsignedp = TREE_UNSIGNED (exp);
+      *punsignedp = BIT_FIELD_REF_UNSIGNED (exp);
     }
   else
     {
       mode = TYPE_MODE (TREE_TYPE (exp));
-      *punsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
+      *punsignedp = TYPE_UNSIGNED (TREE_TYPE (exp));
 
       if (mode == BLKmode)
        size_tree = TYPE_SIZE (TREE_TYPE (exp));
@@ -5810,8 +5482,8 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
             made during type construction.  */
          if (this_offset == 0)
            break;
-         else if (CONTAINS_PLACEHOLDER_P (this_offset))
-           this_offset = build (WITH_RECORD_EXPR, sizetype, this_offset, exp);
+         else
+           this_offset = SUBSTITUTE_PLACEHOLDER_IN_EXPR (this_offset, exp);
 
          offset = size_binop (PLUS_EXPR, offset, this_offset);
          bit_offset = size_binop (PLUS_EXPR, bit_offset,
@@ -5837,35 +5509,16 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
            index = fold (build (MINUS_EXPR, TREE_TYPE (index),
                                 index, low_bound));
 
-         /* If the index has a self-referential type, pass it to a
-            WITH_RECORD_EXPR; if the component size is, pass our
-            component to one.  */
-         if (CONTAINS_PLACEHOLDER_P (index))
-           index = build (WITH_RECORD_EXPR, TREE_TYPE (index), index, exp);
-         if (CONTAINS_PLACEHOLDER_P (unit_size))
-           unit_size = build (WITH_RECORD_EXPR, sizetype, unit_size, array);
-
+         /* If the index has a self-referential type, instantiate it with
+            the object; likewise for the component size.  */
+         index = SUBSTITUTE_PLACEHOLDER_IN_EXPR (index, exp);
+         unit_size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (unit_size, array);
          offset = size_binop (PLUS_EXPR, offset,
                               size_binop (MULT_EXPR,
                                           convert (sizetype, index),
                                           unit_size));
        }
 
-      else if (TREE_CODE (exp) == PLACEHOLDER_EXPR)
-       {
-         tree new = find_placeholder (exp, &placeholder_ptr);
-
-         /* If we couldn't find the replacement, return the PLACEHOLDER_EXPR.
-            We might have been called from tree optimization where we
-            haven't set up an object yet.  */
-         if (new == 0)
-           break;
-         else
-           exp = new;
-
-         continue;
-       }
-
       /* We can go inside most conversions: all NON_VALUE_EXPRs, all normal
         conversions that don't change the mode, and all view conversions
         except those that need to "step up" the alignment.  */
@@ -5950,6 +5603,20 @@ force_operand (rtx value, rtx target)
   rtx subtarget = get_subtarget (target);
   enum rtx_code code = GET_CODE (value);
 
+  /* Check for subreg applied to an expression produced by loop optimizer.  */
+  if (code == SUBREG
+      && GET_CODE (SUBREG_REG (value)) != REG
+      && GET_CODE (SUBREG_REG (value)) != MEM)
+    {
+      value = simplify_gen_subreg (GET_MODE (value),
+                                  force_reg (GET_MODE (SUBREG_REG (value)),
+                                             force_operand (SUBREG_REG (value),
+                                                            NULL_RTX)),
+                                  GET_MODE (SUBREG_REG (value)),
+                                  SUBREG_BYTE (value));
+      code = GET_CODE (value);
+    }
+
   /* Check for a PIC address load.  */
   if ((code == PLUS || code == MINUS)
       && XEXP (value, 0) == pic_offset_table_rtx
@@ -5972,7 +5639,7 @@ force_operand (rtx value, rtx target)
       return target;
     }
 
-  if (GET_RTX_CLASS (code) == '2' || GET_RTX_CLASS (code) == 'c')
+  if (ARITHMETIC_P (value))
     {
       op2 = XEXP (value, 1);
       if (!CONSTANT_P (op2) && !(GET_CODE (op2) == REG && op2 != subtarget))
@@ -6041,7 +5708,7 @@ force_operand (rtx value, rtx target)
                                      target, 1, OPTAB_LIB_WIDEN);
        }
     }
-  if (GET_RTX_CLASS (code) == '1')
+  if (UNARY_P (value))
     {
       op1 = force_operand (XEXP (value, 0), NULL_RTX);
       return expand_simple_unop (GET_MODE (value), code, op1, target, 0);
@@ -6113,7 +5780,7 @@ safe_from_p (rtx x, tree exp, int top_p)
   /* A SAVE_EXPR might appear many times in the expression passed to the
      top-level safe_from_p call, and if it has a complex subexpression,
      examining it multiple times could result in a combinatorial explosion.
-     E.g. on an Alpha running at least 200MHz, a Fortran test case compiled
+     E.g. on an Alpha running at least 200MHz, a Fortran testcase compiled
      with optimization took about 28 minutes to compile -- even though it was
      only a few lines long.  So we mark each SAVE_EXPR we see with TREE_PRIVATE
      and turn that off when we are done.  We keep a list of the SAVE_EXPRs
@@ -6167,7 +5834,7 @@ safe_from_p (rtx x, tree exp, int top_p)
     case '<':
       if (!safe_from_p (x, TREE_OPERAND (exp, 1), 0))
        return 0;
-      /* FALLTHRU */
+      /* Fall through.  */
 
     case '1':
       return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
@@ -6279,7 +5946,7 @@ safe_from_p (rtx x, tree exp, int top_p)
         special handling.  */
       if ((unsigned int) TREE_CODE (exp)
          >= (unsigned int) LAST_AND_UNUSED_TREE_CODE
-         && !(*lang_hooks.safe_from_p) (x, exp))
+         && !lang_hooks.safe_from_p (x, exp))
        return 0;
     }
 
@@ -6323,60 +5990,6 @@ var_rtx (tree exp)
       return 0;
     }
 }
-
-#ifdef MAX_INTEGER_COMPUTATION_MODE
-
-void
-check_max_integer_computation_mode (tree exp)
-{
-  enum tree_code code;
-  enum machine_mode mode;
-
-  /* Strip any NOPs that don't change the mode.  */
-  STRIP_NOPS (exp);
-  code = TREE_CODE (exp);
-
-  /* We must allow conversions of constants to MAX_INTEGER_COMPUTATION_MODE.  */
-  if (code == NOP_EXPR
-      && TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST)
-    return;
-
-  /* First check the type of the overall operation.   We need only look at
-     unary, binary and relational operations.  */
-  if (TREE_CODE_CLASS (code) == '1'
-      || TREE_CODE_CLASS (code) == '2'
-      || TREE_CODE_CLASS (code) == '<')
-    {
-      mode = TYPE_MODE (TREE_TYPE (exp));
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && mode > MAX_INTEGER_COMPUTATION_MODE)
-       internal_error ("unsupported wide integer operation");
-    }
-
-  /* Check operand of a unary op.  */
-  if (TREE_CODE_CLASS (code) == '1')
-    {
-      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && mode > MAX_INTEGER_COMPUTATION_MODE)
-       internal_error ("unsupported wide integer operation");
-    }
-
-  /* Check operands of a binary/comparison op.  */
-  if (TREE_CODE_CLASS (code) == '2' || TREE_CODE_CLASS (code) == '<')
-    {
-      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && mode > MAX_INTEGER_COMPUTATION_MODE)
-       internal_error ("unsupported wide integer operation");
-
-      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1)));
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && mode > MAX_INTEGER_COMPUTATION_MODE)
-       internal_error ("unsupported wide integer operation");
-    }
-}
-#endif
 \f
 /* Return the highest power of two that EXP is known to be a multiple of.
    This is used in updating alignment of MEMs in array references.  */
@@ -6429,7 +6042,7 @@ highest_pow2_factor (tree exp)
       break;
 
     case NON_LVALUE_EXPR:  case NOP_EXPR:  case CONVERT_EXPR:
-    case SAVE_EXPR: case WITH_RECORD_EXPR:
+    case SAVE_EXPR:
       return highest_pow2_factor (TREE_OPERAND (exp, 0));
 
     case COMPOUND_EXPR:
@@ -6447,82 +6060,51 @@ highest_pow2_factor (tree exp)
   return 1;
 }
 
-/* Similar, except that it is known that the expression must be a multiple
-   of the alignment of TYPE.  */
+/* Similar, except that the alignment requirements of TARGET are
+   taken into account.  Assume it is at least as aligned as its
+   type, unless it is a COMPONENT_REF in which case the layout of
+   the structure gives the alignment.  */
 
 static unsigned HOST_WIDE_INT
-highest_pow2_factor_for_type (tree type, tree exp)
+highest_pow2_factor_for_target (tree target, tree exp)
 {
-  unsigned HOST_WIDE_INT type_align, factor;
+  unsigned HOST_WIDE_INT target_align, factor;
 
   factor = highest_pow2_factor (exp);
-  type_align = TYPE_ALIGN (type) / BITS_PER_UNIT;
-  return MAX (factor, type_align);
+  if (TREE_CODE (target) == COMPONENT_REF)
+    target_align = DECL_ALIGN (TREE_OPERAND (target, 1)) / BITS_PER_UNIT;
+  else
+    target_align = TYPE_ALIGN (TREE_TYPE (target)) / BITS_PER_UNIT;
+  return MAX (factor, target_align);
 }
 \f
-/* Return an object on the placeholder list that matches EXP, a
-   PLACEHOLDER_EXPR.  An object "matches" if it is of the type of the
-   PLACEHOLDER_EXPR or a pointer type to it.  For further information, see
-   tree.def.  If no such object is found, return 0.  If PLIST is nonzero, it
-   is a location which initially points to a starting location in the
-   placeholder list (zero means start of the list) and where a pointer into
-   the placeholder list at which the object is found is placed.  */
+/* Subroutine of expand_expr.  Expand the two operands of a binary
+   expression EXP0 and EXP1 placing the results in OP0 and OP1.
+   The value may be stored in TARGET if TARGET is nonzero.  The
+   MODIFIER argument is as documented by expand_expr.  */
 
-tree
-find_placeholder (tree exp, tree *plist)
+static void
+expand_operands (tree exp0, tree exp1, rtx target, rtx *op0, rtx *op1,
+                enum expand_modifier modifier)
 {
-  tree type = TREE_TYPE (exp);
-  tree placeholder_expr;
-
-  for (placeholder_expr
-       = plist && *plist ? TREE_CHAIN (*plist) : placeholder_list;
-       placeholder_expr != 0;
-       placeholder_expr = TREE_CHAIN (placeholder_expr))
+  if (! safe_from_p (target, exp1, 1))
+    target = 0;
+  if (operand_equal_p (exp0, exp1, 0))
     {
-      tree need_type = TYPE_MAIN_VARIANT (type);
-      tree elt;
-
-      /* Find the outermost reference that is of the type we want.  If none,
-        see if any object has a type that is a pointer to the type we
-        want.  */
-      for (elt = TREE_PURPOSE (placeholder_expr); elt != 0;
-          elt = ((TREE_CODE (elt) == COMPOUND_EXPR
-                  || TREE_CODE (elt) == COND_EXPR)
-                 ? TREE_OPERAND (elt, 1)
-                 : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
-                    || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
-                    || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
-                    || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
-                 ? TREE_OPERAND (elt, 0) : 0))
-       if (TYPE_MAIN_VARIANT (TREE_TYPE (elt)) == need_type)
-         {
-           if (plist)
-             *plist = placeholder_expr;
-           return elt;
-         }
-
-      for (elt = TREE_PURPOSE (placeholder_expr); elt != 0;
-          elt
-          = ((TREE_CODE (elt) == COMPOUND_EXPR
-              || TREE_CODE (elt) == COND_EXPR)
-             ? TREE_OPERAND (elt, 1)
-             : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
-                || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
-                || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
-                || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
-             ? TREE_OPERAND (elt, 0) : 0))
-       if (POINTER_TYPE_P (TREE_TYPE (elt))
-           && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (elt)))
-               == need_type))
-         {
-           if (plist)
-             *plist = placeholder_expr;
-           return build1 (INDIRECT_REF, need_type, elt);
-         }
+      *op0 = expand_expr (exp0, target, VOIDmode, modifier);
+      *op1 = copy_rtx (*op0);
+    }
+  else
+    {
+      /* If we need to preserve evaluation order, copy exp0 into its own
+        temporary variable so that it can't be clobbered by exp1.  */
+      if (flag_evaluation_order && TREE_SIDE_EFFECTS (exp1))
+       exp0 = save_expr (exp0);
+      *op0 = expand_expr (exp0, target, VOIDmode, modifier);
+      *op1 = expand_expr (exp1, NULL_RTX, VOIDmode, modifier);
     }
-
-  return 0;
 }
+
 \f
 /* expand_expr: generate code for computing expression EXP.
    An rtx for the computed value is returned.  The value is never null.
@@ -6564,14 +6146,21 @@ find_placeholder (tree exp, tree *plist)
    marked TARGET so that it's safe from being trashed by libcalls.  We
    don't want to use TARGET for anything but the final result;
    Intermediate values must go elsewhere.   Additionally, calls to
-   emit_block_move will be flagged with BLOCK_OP_CALL_PARM.  */
+   emit_block_move will be flagged with BLOCK_OP_CALL_PARM.  
+
+   If EXP is a VAR_DECL whose DECL_RTL was a MEM with an invalid
+   address, and ALT_RTL is non-NULL, then *ALT_RTL is set to the
+   DECL_RTL of the VAR_DECL.  *ALT_RTL is also set if EXP is a
+   COMPOUND_EXPR whose second argument is such a VAR_DECL, and so on
+   recursively.  */
 
 rtx
-expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier modifier)
+expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
+                 enum expand_modifier modifier, rtx *alt_rtl)
 {
   rtx op0, op1, temp;
   tree type = TREE_TYPE (exp);
-  int unsignedp = TREE_UNSIGNED (type);
+  int unsignedp;
   enum machine_mode mode;
   enum tree_code code = TREE_CODE (exp);
   optab this_optab;
@@ -6589,6 +6178,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
     }
 
   mode = TYPE_MODE (type);
+  unsignedp = TYPE_UNSIGNED (type);
+
   /* Use subtarget as the target for operand 0 of a binary operation.  */
   subtarget = get_subtarget (target);
   original_target = target;
@@ -6651,49 +6242,6 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       target = 0;
     }
 
-#ifdef MAX_INTEGER_COMPUTATION_MODE
-  /* Only check stuff here if the mode we want is different from the mode
-     of the expression; if it's the same, check_max_integer_computation_mode
-     will handle it.  Do we really need to check this stuff at all?  */
-
-  if (target
-      && GET_MODE (target) != mode
-      && TREE_CODE (exp) != INTEGER_CST
-      && TREE_CODE (exp) != PARM_DECL
-      && TREE_CODE (exp) != ARRAY_REF
-      && TREE_CODE (exp) != ARRAY_RANGE_REF
-      && TREE_CODE (exp) != COMPONENT_REF
-      && TREE_CODE (exp) != BIT_FIELD_REF
-      && TREE_CODE (exp) != INDIRECT_REF
-      && TREE_CODE (exp) != CALL_EXPR
-      && TREE_CODE (exp) != VAR_DECL
-      && TREE_CODE (exp) != RTL_EXPR)
-    {
-      enum machine_mode mode = GET_MODE (target);
-
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && mode > MAX_INTEGER_COMPUTATION_MODE)
-       internal_error ("unsupported wide integer operation");
-    }
-
-  if (tmode != mode
-      && TREE_CODE (exp) != INTEGER_CST
-      && TREE_CODE (exp) != PARM_DECL
-      && TREE_CODE (exp) != ARRAY_REF
-      && TREE_CODE (exp) != ARRAY_RANGE_REF
-      && TREE_CODE (exp) != COMPONENT_REF
-      && TREE_CODE (exp) != BIT_FIELD_REF
-      && TREE_CODE (exp) != INDIRECT_REF
-      && TREE_CODE (exp) != VAR_DECL
-      && TREE_CODE (exp) != CALL_EXPR
-      && TREE_CODE (exp) != RTL_EXPR
-      && GET_MODE_CLASS (tmode) == MODE_INT
-      && tmode > MAX_INTEGER_COMPUTATION_MODE)
-    internal_error ("unsupported wide integer operation");
-
-  check_max_integer_computation_mode (exp);
-#endif
-
   /* If will do cse, generate all results into pseudo registers
      since 1) that allows cse to find more things
      and 2) otherwise cse could produce an insn the machine
@@ -6704,7 +6252,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
   if (! cse_not_expected && mode != BLKmode && target
       && (GET_CODE (target) != REG || REGNO (target) < FIRST_PSEUDO_REGISTER)
       && ! (code == CONSTRUCTOR && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
-      && ! (code == CALL_EXPR && aggregate_value_p (exp)))
+      && ! (code == CALL_EXPR && aggregate_value_p (exp, exp)))
     target = 0;
 
   switch (code)
@@ -6732,8 +6280,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
     case PARM_DECL:
       if (!DECL_RTL_SET_P (exp))
        {
-         error ("%Hprior parameter's size depends on '%D'",
-                 &DECL_SOURCE_LOCATION (exp), exp);
+         error ("%Jprior parameter's size depends on '%D'", exp, exp);
          return CONST0_RTX (mode);
        }
 
@@ -6786,7 +6333,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          DECL_NONLOCAL (exp) = 1;
          if (DECL_NO_STATIC_CHAIN (current_function_decl))
            abort ();
-         (*lang_hooks.mark_addressable) (exp);
+         lang_hooks.mark_addressable (exp);
          if (GET_CODE (DECL_RTL (exp)) != MEM)
            abort ();
          addr = XEXP (DECL_RTL (exp), 0);
@@ -6820,8 +6367,12 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                                       XEXP (DECL_RTL (exp), 0))
                   || (flag_force_addr
                       && GET_CODE (XEXP (DECL_RTL (exp), 0)) != REG)))
-       temp = replace_equiv_address (DECL_RTL (exp),
-                                     copy_rtx (XEXP (DECL_RTL (exp), 0)));
+       {
+         if (alt_rtl)
+           *alt_rtl = DECL_RTL (exp);
+         temp = replace_equiv_address (DECL_RTL (exp),
+                                       copy_rtx (XEXP (DECL_RTL (exp), 0)));
+       }
 
       /* If we got something, return it.  But first, set the alignment
         if the address is a register.  */
@@ -6932,14 +6483,23 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
     case EXPR_WITH_FILE_LOCATION:
       {
        rtx to_return;
-       location_t saved_loc = input_location;
+       struct file_stack fs;
+
+       fs.location = input_location;
+       fs.next = expr_wfl_stack;
        input_filename = EXPR_WFL_FILENAME (exp);
        input_line = EXPR_WFL_LINENO (exp);
+       expr_wfl_stack = &fs;
        if (EXPR_WFL_EMIT_LINE_NOTE (exp))
          emit_line_note (input_location);
        /* Possibly avoid switching back and forth here.  */
-       to_return = expand_expr (EXPR_WFL_NODE (exp), target, tmode, modifier);
-       input_location = saved_loc;
+       to_return = expand_expr (EXPR_WFL_NODE (exp),
+                                (ignore ? const0_rtx : target),
+                                tmode, modifier);
+       if (expr_wfl_stack != &fs)
+         abort ();
+       input_location = fs.location;
+       expr_wfl_stack = fs.next;
        return to_return;
       }
 
@@ -7036,35 +6596,10 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        rtx temp;
        temp = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
        TREE_OPERAND (exp, 0)
-         = (*lang_hooks.unsave_expr_now) (TREE_OPERAND (exp, 0));
-       return temp;
-      }
-
-    case PLACEHOLDER_EXPR:
-      {
-       tree old_list = placeholder_list;
-       tree placeholder_expr = 0;
-
-       exp = find_placeholder (exp, &placeholder_expr);
-       if (exp == 0)
-         abort ();
-
-       placeholder_list = TREE_CHAIN (placeholder_expr);
-       temp = expand_expr (exp, original_target, tmode, modifier);
-       placeholder_list = old_list;
+         = lang_hooks.unsave_expr_now (TREE_OPERAND (exp, 0));
        return temp;
       }
 
-    case WITH_RECORD_EXPR:
-      /* Put the object on the placeholder list, expand our first operand,
-        and pop the list.  */
-      placeholder_list = tree_cons (TREE_OPERAND (exp, 1), NULL_TREE,
-                                   placeholder_list);
-      target = expand_expr (TREE_OPERAND (exp, 0), original_target, tmode,
-                           modifier);
-      placeholder_list = TREE_CHAIN (placeholder_list);
-      return target;
-
     case GOTO_EXPR:
       if (TREE_CODE (TREE_OPERAND (exp, 0)) == LABEL_DECL)
        expand_goto (TREE_OPERAND (exp, 0));
@@ -7111,7 +6646,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        /* Mark the corresponding BLOCK for output in its proper place.  */
        if (TREE_OPERAND (exp, 2) != 0
            && ! TREE_USED (TREE_OPERAND (exp, 2)))
-         (*lang_hooks.decls.insert_block) (TREE_OPERAND (exp, 2));
+         lang_hooks.decls.insert_block (TREE_OPERAND (exp, 2));
 
        /* If VARS have not yet been expanded, expand them now.  */
        while (vars)
@@ -7139,6 +6674,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        }
       preserve_rtl_expr_result (RTL_EXPR_RTL (exp));
       free_temps_for_rtl_expr (exp);
+      if (alt_rtl)
+       *alt_rtl = RTL_EXPR_ALT_RTL (exp);
       return RTL_EXPR_RTL (exp);
 
     case CONSTRUCTOR:
@@ -7311,7 +6848,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                 && modifier != EXPAND_MEMORY
                 && TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
                 && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
-                && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK)
+                && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK
+                && targetm.binds_local_p (array))
          {
            if (TREE_CODE (index) == INTEGER_CST)
              {
@@ -7382,7 +6920,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                    enum machine_mode imode
                      = TYPE_MODE (TREE_TYPE (TREE_PURPOSE (elt)));
 
-                   if (TREE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
+                   if (TYPE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
                      {
                        op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1);
                        op0 = expand_and (imode, op0, op1, target);
@@ -7476,7 +7014,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                                          (TYPE_QUALS (TREE_TYPE (tem))
                                           | TYPE_QUAL_CONST));
                rtx memloc = assign_temp (nt, 1, 1, 1);
-               
+
                emit_move_insn (memloc, op0);
                op0 = memloc;
              }
@@ -7498,10 +7036,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
              offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
 #endif
 
-           /* A constant address in OP0 can have VOIDmode, we must not try
-              to call force_reg for that case.  Avoid that case.  */
-           if (GET_CODE (op0) == MEM
-               && GET_MODE (op0) == BLKmode
+           if (GET_MODE (op0) == BLKmode
+               /* A constant address in OP0 can have VOIDmode, we must
+                  not try to call force_reg in that case.  */
                && GET_MODE (XEXP (op0, 0)) != VOIDmode
                && bitsize != 0
                && (bitpos % bitsize) == 0
@@ -7558,7 +7095,10 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
               fetch it as a bit field.  */
            || (mode1 != BLKmode
                && (((TYPE_ALIGN (TREE_TYPE (tem)) < GET_MODE_ALIGNMENT (mode)
-                     || (bitpos % GET_MODE_ALIGNMENT (mode) != 0))
+                     || (bitpos % GET_MODE_ALIGNMENT (mode) != 0)
+                     || (GET_CODE (op0) == MEM
+                         && (MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode1)
+                             || (bitpos % GET_MODE_ALIGNMENT (mode1) != 0))))
                     && ((modifier == EXPAND_CONST_ADDRESS
                          || modifier == EXPAND_INITIALIZER)
                         ? STRICT_ALIGNMENT
@@ -7583,6 +7123,12 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
 
            if (ext_mode == BLKmode)
              {
+               if (target == 0)
+                 target = assign_temp (type, 0, 1, 1);
+
+               if (bitsize == 0)
+                 return target;
+
                /* In this case, BITPOS must start at a byte boundary and
                   TARGET, if specified, must be a MEM.  */
                if (GET_CODE (op0) != MEM
@@ -7590,11 +7136,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                    || bitpos % BITS_PER_UNIT != 0)
                  abort ();
 
-               op0 = adjust_address (op0, VOIDmode, bitpos / BITS_PER_UNIT);
-               if (target == 0)
-                 target = assign_temp (type, 0, 1, 1);
-
-               emit_block_move (target, op0,
+               emit_block_move (target,
+                                adjust_address (op0, VOIDmode,
+                                                bitpos / BITS_PER_UNIT),
                                 GEN_INT ((bitsize + BITS_PER_UNIT - 1)
                                          / BITS_PER_UNIT),
                                 (modifier == EXPAND_STACK_PARM
@@ -7625,12 +7169,19 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                                            - bitsize),
                                  op0, 1);
 
+           /* If the result type is BLKmode, store the data into a temporary
+              of the appropriate type, but with the mode corresponding to the
+              mode for the data we have (op0's mode).  It's tempting to make
+              this a constant type, since we know it's only being stored once,
+              but that can cause problems if we are taking the address of this
+              COMPONENT_REF because the MEM of any reference via that address
+              will have flags corresponding to the type, which will not
+              necessarily be constant.  */
            if (mode == BLKmode)
              {
-               rtx new = assign_temp (build_qualified_type
-                                      ((*lang_hooks.types.type_for_mode)
-                                       (ext_mode, 0),
-                                       TYPE_QUAL_CONST), 0, 1, 1);
+               rtx new
+                 = assign_stack_temp_for_type
+                   (ext_mode, GET_MODE_BITSIZE (ext_mode), 0, type);
 
                emit_move_insn (new, op0);
                op0 = copy_rtx (new);
@@ -7728,7 +7279,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
 
        tree set = TREE_OPERAND (exp, 0);
        tree index = TREE_OPERAND (exp, 1);
-       int iunsignedp = TREE_UNSIGNED (TREE_TYPE (index));
+       int iunsignedp = TYPE_UNSIGNED (TREE_TYPE (index));
        tree set_type = TREE_TYPE (set);
        tree set_low_bound = TYPE_MIN_VALUE (TYPE_DOMAIN (set_type));
        tree set_high_bound = TYPE_MAX_VALUE (TYPE_DOMAIN (set_type));
@@ -7855,8 +7406,10 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        {
          if (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
              == BUILT_IN_FRONTEND)
+         /* ??? Use (*fun) form because expand_expr is a macro.  */
            return (*lang_hooks.expand_expr) (exp, original_target,
-                                             tmode, modifier);
+                                             tmode, modifier,
+                                             alt_rtl);
          else
            return expand_builtin (exp, target, subtarget, tmode, ignore);
        }
@@ -7887,7 +7440,12 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
            }
 
          if (target == 0)
-           target = assign_temp (type, 0, 1, 1);
+           {
+             if (TYPE_MODE (type) != BLKmode)
+               target = gen_reg_rtx (TYPE_MODE (type));
+             else
+               target = assign_temp (type, 0, 1, 1);
+           }
 
          if (GET_CODE (target) == MEM)
            /* Store data into beginning of memory target.  */
@@ -7919,7 +7477,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          /* If the signedness of the conversion differs and OP0 is
             a promoted SUBREG, clear that indication since we now
             have to do the proper extension.  */
-         if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))) != unsignedp
+         if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))) != unsignedp
              && GET_CODE (op0) == SUBREG)
            SUBREG_PROMOTED_VAR_P (op0) = 0;
 
@@ -7942,7 +7500,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                                                               inner_mode));
          else
            return convert_modes (mode, inner_mode, op0,
-                                 TREE_UNSIGNED (inner_type));
+                                 TYPE_UNSIGNED (inner_type));
        }
 
       if (modifier == EXPAND_INITIALIZER)
@@ -7951,10 +7509,10 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       if (target == 0)
        return
          convert_to_mode (mode, op0,
-                          TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+                          TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
       else
        convert_move (target, op0,
-                     TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+                     TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
       return target;
 
     case VIEW_CONVERT_EXPR:
@@ -8131,9 +7689,6 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
            }
        }
 
-      if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
-       subtarget = 0;
-
       /* No sense saving up arithmetic to be done
         if it's all in the wrong mode to form part of an address.
         And force_operand won't know whether to sign-extend or
@@ -8141,12 +7696,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       if ((modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
          || mode != ptr_mode)
        {
-         op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-         if (! operand_equal_p (TREE_OPERAND (exp, 0),
-                                TREE_OPERAND (exp, 1), 0))
-           op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
-         else
-           op1 = op0;
+         expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                          subtarget, &op0, &op1, 0);
          if (op0 == const0_rtx)
            return op1;
          if (op1 == const0_rtx)
@@ -8154,13 +7705,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          goto binop2;
        }
 
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, modifier);
-      if (! operand_equal_p (TREE_OPERAND (exp, 0),
-                            TREE_OPERAND (exp, 1), 0))
-       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
-                          VOIDmode, modifier);
-      else
-       op1 = op0;
+      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                      subtarget, &op0, &op1, modifier);
       return simplify_gen_binary (PLUS, mode, op0, op1);
 
     case MINUS_EXPR:
@@ -8173,10 +7719,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          && really_constant_p (TREE_OPERAND (exp, 0))
          && really_constant_p (TREE_OPERAND (exp, 1)))
        {
-         rtx op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode,
-                                modifier);
-         rtx op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode,
-                                modifier);
+         expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                          NULL_RTX, &op0, &op1, modifier);
 
          /* If the last operand is a CONST_INT, use plus_constant of
             the negated constant.  Else make the MINUS.  */
@@ -8198,11 +7742,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          || mode != ptr_mode)
        goto binop;
 
-      if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
-       subtarget = 0;
-
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, modifier);
-      op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, modifier);
+      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                      subtarget, &op0, &op1, modifier);
 
       /* Convert A - const to A + (-const).  */
       if (GET_CODE (op1) == CONST_INT)
@@ -8235,16 +7776,6 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
                             EXPAND_SUM);
 
-         /* If we knew for certain that this is arithmetic for an array
-            reference, and we knew the bounds of the array, then we could
-            apply the distributive law across (PLUS X C) for constant C.
-            Without such knowledge, we risk overflowing the computation
-            when both X and C are large, but X+C isn't.  */
-         /* ??? Could perhaps special-case EXP being unsigned and C being
-            positive.  In that case we are certain that X+C is no smaller
-            than X and so the transformed expression will overflow iff the
-            original would have.  */
-
          if (GET_CODE (op0) != REG)
            op0 = force_operand (op0, NULL_RTX);
          if (GET_CODE (op0) != REG)
@@ -8255,9 +7786,6 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                                             TYPE_MODE (TREE_TYPE (exp1))));
        }
 
-      if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
-       subtarget = 0;
-
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
 
@@ -8278,39 +7806,43 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                   || exact_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))) < 0))
              ||
              (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
-              && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
-                  ==
-                  TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))))
+              && (TYPE_PRECISION (TREE_TYPE
+                                  (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
+                  == TYPE_PRECISION (TREE_TYPE
+                                     (TREE_OPERAND
+                                      (TREE_OPERAND (exp, 0), 0))))
               /* If both operands are extended, they must either both
                  be zero-extended or both be sign-extended.  */
-              && (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
-                  ==
-                  TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))))))
-       {
-         enum machine_mode innermode
-           = TYPE_MODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)));
-         optab other_optab = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
-                       ? smul_widen_optab : umul_widen_optab);
-         this_optab = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
-                       ? umul_widen_optab : smul_widen_optab);
+              && (TYPE_UNSIGNED (TREE_TYPE
+                                 (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
+                  == TYPE_UNSIGNED (TREE_TYPE
+                                    (TREE_OPERAND
+                                     (TREE_OPERAND (exp, 0), 0)))))))
+       {
+         tree op0type = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0));
+         enum machine_mode innermode = TYPE_MODE (op0type);
+         bool zextend_p = TYPE_UNSIGNED (op0type);
+         optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;
+         this_optab = zextend_p ? umul_widen_optab : smul_widen_optab;
+
          if (mode == GET_MODE_WIDER_MODE (innermode))
            {
              if (this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
                {
-                 op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
-                                    NULL_RTX, VOIDmode, 0);
                  if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
-                   op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
-                                      VOIDmode, 0);
+                   expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
+                                    TREE_OPERAND (exp, 1),
+                                    NULL_RTX, &op0, &op1, 0);
                  else
-                   op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
-                                      NULL_RTX, VOIDmode, 0);
+                   expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
+                                    TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
+                                    NULL_RTX, &op0, &op1, 0);
                  goto binop2;
                }
              else if (other_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
                       && innermode == word_mode)
                {
-                 rtx htem;
+                 rtx htem, hipart;
                  op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
                                     NULL_RTX, VOIDmode, 0);
                  if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
@@ -8323,22 +7855,18 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
                                       NULL_RTX, VOIDmode, 0);
                  temp = expand_binop (mode, other_optab, op0, op1, target,
                                       unsignedp, OPTAB_LIB_WIDEN);
-                 htem = expand_mult_highpart_adjust (innermode,
-                                                     gen_highpart (innermode, temp),
-                                                     op0, op1,
-                                                     gen_highpart (innermode, temp),
-                                                     unsignedp);
-                 emit_move_insn (gen_highpart (innermode, temp), htem);
+                 hipart = gen_highpart (innermode, temp);
+                 htem = expand_mult_highpart_adjust (innermode, hipart,
+                                                     op0, op1, hipart,
+                                                     zextend_p);
+                 if (htem != hipart)
+                   emit_move_insn (hipart, htem);
                  return temp;
                }
            }
        }
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      if (! operand_equal_p (TREE_OPERAND (exp, 0),
-                            TREE_OPERAND (exp, 1), 0))
-       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
-      else
-       op1 = op0;
+      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                      subtarget, &op0, &op1, 0);
       return expand_mult (mode, op0, op1, target, unsignedp);
 
     case TRUNC_DIV_EXPR:
@@ -8346,15 +7874,13 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
     case CEIL_DIV_EXPR:
     case ROUND_DIV_EXPR:
     case EXACT_DIV_EXPR:
-      if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
-       subtarget = 0;
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
       /* Possible optimization: compute the dividend with EXPAND_SUM
         then if the divisor is constant can optimize the case
         where some terms of the dividend have coeffs divisible by it.  */
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
+      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                      subtarget, &op0, &op1, 0);
       return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
 
     case RDIV_EXPR:
@@ -8376,12 +7902,10 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
     case FLOOR_MOD_EXPR:
     case CEIL_MOD_EXPR:
     case ROUND_MOD_EXPR:
-      if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
-       subtarget = 0;
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
+      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                      subtarget, &op0, &op1, 0);
       return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
 
     case FIX_ROUND_EXPR:
@@ -8406,7 +7930,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        op0 = copy_to_mode_reg (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
                                op0);
       expand_float (target, op0,
-                   TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+                   TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
       return target;
 
     case NEGATE_EXPR:
@@ -8433,7 +7957,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
 
       /* Unsigned abs is simply the operand.  Testing here means we don't
         risk generating incorrect code below.  */
-      if (TREE_UNSIGNED (type))
+      if (TYPE_UNSIGNED (type))
        return op0;
 
       return expand_abs (mode, op0, target, unsignedp,
@@ -8444,19 +7968,18 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       target = original_target;
       if (target == 0
          || modifier == EXPAND_STACK_PARM
-         || ! safe_from_p (target, TREE_OPERAND (exp, 1), 1)
          || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
          || GET_MODE (target) != mode
          || (GET_CODE (target) == REG
              && REGNO (target) < FIRST_PSEUDO_REGISTER))
        target = gen_reg_rtx (mode);
-      op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
-      op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
+      expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                      target, &op0, &op1, 0);
 
       /* First try to do it with a special MIN or MAX instruction.
         If that does not win, use a conditional jump to select the proper
         value.  */
-      this_optab = (TREE_UNSIGNED (type)
+      this_optab = (unsignedp
                    ? (code == MIN_EXPR ? umin_optab : umax_optab)
                    : (code == MIN_EXPR ? smin_optab : smax_optab));
 
@@ -8471,6 +7994,14 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       if (GET_CODE (target) == MEM)
        target = gen_reg_rtx (mode);
 
+      /* If op1 was placed in target, swap op0 and op1.  */
+      if (target != op0 && target == op1)
+       {
+         rtx tem = op0;
+         op0 = op1;
+         op1 = tem;
+       }
+
       if (target != op0)
        emit_move_insn (target, op0);
 
@@ -8482,18 +8013,16 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          && ! can_compare_p (GE, mode, ccp_jump))
        {
          if (code == MAX_EXPR)
-           do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type),
-                                         target, op1, NULL_RTX, op0);
+           do_jump_by_parts_greater_rtx (mode, unsignedp, target, op1,
+                                         NULL_RTX, op0);
          else
-           do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type),
-                                         op1, target, NULL_RTX, op0);
+           do_jump_by_parts_greater_rtx (mode, unsignedp, op1, target,
+                                         NULL_RTX, op0);
        }
       else
        {
-         int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)));
          do_compare_rtx_and_jump (target, op1, code == MAX_EXPR ? GE : LE,
-                                  unsignedp, mode, NULL_RTX, NULL_RTX,
-                                  op0);
+                                  unsignedp, mode, NULL_RTX, NULL_RTX, op0);
        }
       emit_move_insn (target, op1);
       emit_label (op0);
@@ -8508,43 +8037,6 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
        abort ();
       return temp;
 
-    case FFS_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      if (modifier == EXPAND_STACK_PARM)
-       target = 0;
-      temp = expand_unop (mode, ffs_optab, op0, target, 1);
-      if (temp == 0)
-       abort ();
-      return temp;
-
-    case CLZ_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      temp = expand_unop (mode, clz_optab, op0, target, 1);
-      if (temp == 0)
-       abort ();
-      return temp;
-
-    case CTZ_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      temp = expand_unop (mode, ctz_optab, op0, target, 1);
-      if (temp == 0)
-       abort ();
-      return temp;
-
-    case POPCOUNT_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      temp = expand_unop (mode, popcount_optab, op0, target, 1);
-      if (temp == 0)
-       abort ();
-      return temp;
-
-    case PARITY_EXPR:
-      op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-      temp = expand_unop (mode, parity_optab, op0, target, 1);
-      if (temp == 0)
-       abort ();
-      return temp;
-
       /* ??? Can optimize bitwise operations with one arg constant.
         Can optimize (a bitwise1 n) bitwise2 (a bitwise3 b)
         and (a bitwise1 b) bitwise2 b (etc)
@@ -8687,9 +8179,9 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
     case COMPOUND_EXPR:
       expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
       emit_queue ();
-      return expand_expr (TREE_OPERAND (exp, 1),
-                         (ignore ? const0_rtx : target),
-                         VOIDmode, modifier);
+      return expand_expr_real (TREE_OPERAND (exp, 1),
+                              (ignore ? const0_rtx : target),
+                              VOIDmode, modifier, alt_rtl);
 
     case COND_EXPR:
       /* If we would have a "singleton" (see below) were it not for a
@@ -8921,8 +8413,12 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
            jumpif (TREE_OPERAND (exp, 0), op0);
 
            start_cleanup_deferral ();
-           store_expr (TREE_OPERAND (exp, 2), temp,
-                       modifier == EXPAND_STACK_PARM ? 2 : 0);
+           if (TREE_TYPE (TREE_OPERAND (exp, 2)) != void_type_node)
+             store_expr (TREE_OPERAND (exp, 2), temp,
+                         modifier == EXPAND_STACK_PARM ? 2 : 0);
+           else
+             expand_expr (TREE_OPERAND (exp, 2),
+                          ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
            op1 = op0;
          }
        else if (temp
@@ -8942,8 +8438,12 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
            jumpifnot (TREE_OPERAND (exp, 0), op0);
 
            start_cleanup_deferral ();
-           store_expr (TREE_OPERAND (exp, 1), temp,
-                       modifier == EXPAND_STACK_PARM ? 2 : 0);
+           if (TREE_TYPE (TREE_OPERAND (exp, 1)) != void_type_node)
+             store_expr (TREE_OPERAND (exp, 1), temp,
+                         modifier == EXPAND_STACK_PARM ? 2 : 0);
+           else
+             expand_expr (TREE_OPERAND (exp, 1),
+                          ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
            op1 = op0;
          }
        else
@@ -9040,7 +8540,7 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
 
                if (TREE_OPERAND (exp, 2) == 0)
                  TREE_OPERAND (exp, 2)
-                   = (*lang_hooks.maybe_build_cleanup) (slot);
+                   = lang_hooks.maybe_build_cleanup (slot);
                cleanups = TREE_OPERAND (exp, 2);
              }
          }
@@ -9248,11 +8748,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
            {
              op0 = XEXP (op0, 0);
-#ifdef POINTERS_EXTEND_UNSIGNED
-             if (GET_MODE (op0) == Pmode && GET_MODE (op0) != mode
-                 && mode == ptr_mode)
+             if (GET_MODE (op0) == Pmode && mode == ptr_mode)
                op0 = convert_memory_address (ptr_mode, op0);
-#endif
              return op0;
            }
 
@@ -9313,11 +8810,8 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
          && ! REG_USERVAR_P (op0))
        mark_reg_pointer (op0, TYPE_ALIGN (TREE_TYPE (type)));
 
-#ifdef POINTERS_EXTEND_UNSIGNED
-      if (GET_MODE (op0) == Pmode && GET_MODE (op0) != mode
-         && mode == ptr_mode)
+      if (GET_MODE (op0) == Pmode && mode == ptr_mode)
        op0 = convert_memory_address (ptr_mode, op0);
-#endif
 
       return op0;
 
@@ -9500,16 +8994,16 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
       abort ();
 
     default:
-      return (*lang_hooks.expand_expr) (exp, original_target, tmode, modifier);
+      /* ??? Use (*fun) form because expand_expr is a macro.  */
+      return (*lang_hooks.expand_expr) (exp, original_target, tmode,
+                                       modifier, alt_rtl);
     }
 
   /* Here to do an ordinary binary operator, generating an instruction
      from the optab already placed in `this_optab'.  */
  binop:
-  if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
-    subtarget = 0;
-  op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
-  op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
+  expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
+                  subtarget, &op0, &op1, 0);
  binop2:
   if (modifier == EXPAND_STACK_PARM)
     target = 0;
@@ -9527,18 +9021,18 @@ expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier
 static int
 is_aligning_offset (tree offset, tree exp)
 {
-  /* Strip off any conversions and WITH_RECORD_EXPR nodes.  */
+  /* Strip off any conversions.  */
   while (TREE_CODE (offset) == NON_LVALUE_EXPR
         || TREE_CODE (offset) == NOP_EXPR
-        || TREE_CODE (offset) == CONVERT_EXPR
-        || TREE_CODE (offset) == WITH_RECORD_EXPR)
+        || TREE_CODE (offset) == CONVERT_EXPR)
     offset = TREE_OPERAND (offset, 0);
 
   /* We must now have a BIT_AND_EXPR with a constant that is one less than
      power of 2 and which is larger than BIGGEST_ALIGNMENT.  */
   if (TREE_CODE (offset) != BIT_AND_EXPR
       || !host_integerp (TREE_OPERAND (offset, 1), 1)
-      || compare_tree_int (TREE_OPERAND (offset, 1), BIGGEST_ALIGNMENT) <= 0
+      || compare_tree_int (TREE_OPERAND (offset, 1), 
+                          BIGGEST_ALIGNMENT / BITS_PER_UNIT) <= 0
       || !exact_log2 (tree_low_cst (TREE_OPERAND (offset, 1), 1) + 1) < 0)
     return 0;
 
@@ -9559,13 +9053,8 @@ is_aligning_offset (tree offset, tree exp)
         || TREE_CODE (offset) == CONVERT_EXPR)
     offset = TREE_OPERAND (offset, 0);
 
-  /* This must now be the address either of EXP or of a PLACEHOLDER_EXPR
-     whose type is the same as EXP.  */
-  return (TREE_CODE (offset) == ADDR_EXPR
-         && (TREE_OPERAND (offset, 0) == exp
-             || (TREE_CODE (TREE_OPERAND (offset, 0)) == PLACEHOLDER_EXPR
-                 && (TREE_TYPE (TREE_OPERAND (offset, 0))
-                     == TREE_TYPE (exp)))));
+  /* This must now be the address of EXP.  */
+  return TREE_CODE (offset) == ADDR_EXPR && TREE_OPERAND (offset, 0) == exp;
 }
 \f
 /* Return the tree node if an ARG corresponds to a string constant or zero
@@ -9750,7 +9239,7 @@ expand_increment (tree exp, int post, int ignore)
     {
       /* We have a true reference to the value in OP0.
         If there is an insn to add or subtract in this mode, queue it.
-        Queueing the increment insn avoids the register shuffling
+        Queuing the increment insn avoids the register shuffling
         that often results if we must increment now and first save
         the old value for subsequent use.  */
 
@@ -9803,7 +9292,7 @@ expand_increment (tree exp, int post, int ignore)
 
   /* Increment however we can.  */
   op1 = expand_binop (mode, this_optab, value, op1, op0,
-                     TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
+                     TYPE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
 
   /* Make sure the value is stored into OP0.  */
   if (op1 != op0)
@@ -9863,7 +9352,7 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
 
   type = TREE_TYPE (arg0);
   operand_mode = TYPE_MODE (type);
-  unsignedp = TREE_UNSIGNED (type);
+  unsignedp = TYPE_UNSIGNED (type);
 
   /* We won't bother with BLKmode store-flag operations because it would mean
      passing a lot of information to emit_store_flag.  */
@@ -9972,9 +9461,9 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
       && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
       && integer_pow2p (TREE_OPERAND (arg0, 1)))
     {
-      tree type = (*lang_hooks.types.type_for_mode) (mode, unsignedp);
+      tree type = lang_hooks.types.type_for_mode (mode, unsignedp);
       return expand_expr (fold_single_bit_test (code == NE ? NE_EXPR : EQ_EXPR,
-                                               arg0, arg1, type), 
+                                               arg0, arg1, type),
                          target, VOIDmode, EXPAND_NORMAL);
     }
 
@@ -10004,12 +9493,10 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
     }
 
   if (! get_subtarget (target)
-      || GET_MODE (subtarget) != operand_mode
-      || ! safe_from_p (subtarget, arg1, 1))
+      || GET_MODE (subtarget) != operand_mode)
     subtarget = 0;
 
-  op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
-  op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+  expand_operands (arg0, arg1, subtarget, &op0, &op1, 0);
 
   if (target == 0)
     target = gen_reg_rtx (mode);
@@ -10118,7 +9605,7 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
     {
       if (TYPE_MODE (index_type) != index_mode)
        {
-         index_expr = convert ((*lang_hooks.types.type_for_size)
+         index_expr = convert (lang_hooks.types.type_for_size
                                (index_bits, 0), index_expr);
          index_type = TREE_TYPE (index_expr);
        }
@@ -10138,7 +9625,7 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
 
   op_mode = insn_data[(int) CODE_FOR_casesi].operand[1].mode;
   op1 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (minval)),
-                      op1, TREE_UNSIGNED (TREE_TYPE (minval)));
+                      op1, TYPE_UNSIGNED (TREE_TYPE (minval)));
   if (! (*insn_data[(int) CODE_FOR_casesi].operand[1].predicate)
       (op1, op_mode))
     op1 = copy_to_mode_reg (op_mode, op1);
@@ -10147,7 +9634,7 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
 
   op_mode = insn_data[(int) CODE_FOR_casesi].operand[2].mode;
   op2 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (range)),
-                      op2, TREE_UNSIGNED (TREE_TYPE (range)));
+                      op2, TYPE_UNSIGNED (TREE_TYPE (range)));
   if (! (*insn_data[(int) CODE_FOR_casesi].operand[2].predicate)
       (op2, op_mode))
     op2 = copy_to_mode_reg (op_mode, op2);
@@ -10199,7 +9686,7 @@ do_tablejump (rtx index, enum machine_mode mode, rtx range, rtx table_label,
   if (mode != Pmode)
     index = convert_to_mode (Pmode, index, 1);
 
-  /* Don't let a MEM slip thru, because then INDEX that comes
+  /* Don't let a MEM slip through, because then INDEX that comes
      out of PIC_CASE_VECTOR_ADDRESS won't be a valid address,
      and break_out_memory_refs will go to work on it and mess it up.  */
 #ifdef PIC_CASE_VECTOR_ADDRESS
@@ -10261,7 +9748,7 @@ try_tablejump (tree index_type, tree index_expr, tree minval, tree range,
                               TYPE_MODE (TREE_TYPE (range)),
                               expand_expr (range, NULL_RTX,
                                            VOIDmode, 0),
-                              TREE_UNSIGNED (TREE_TYPE (range))),
+                              TYPE_UNSIGNED (TREE_TYPE (range))),
                table_label, default_label);
   return 1;
 }