OSDN Git Service

ch:
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index daa06d0..c36d61f 100644 (file)
@@ -1,5 +1,6 @@
 /* Convert tree expression to rtl instructions, for GNU compiler.
-   Copyright (C) 1988, 92-98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
+   Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -18,7 +19,6 @@ along with GNU CC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-
 #include "config.h"
 #include "system.h"
 #include "machmode.h"
@@ -33,16 +33,30 @@ Boston, MA 02111-1307, USA.  */
 #include "insn-flags.h"
 #include "insn-codes.h"
 #include "insn-config.h"
-/* Include expr.h after insn-config.h so we get HAVE_conditional_move. */
+/* Include expr.h after insn-config.h so we get HAVE_conditional_move.  */
 #include "expr.h"
 #include "recog.h"
+#include "reload.h"
 #include "output.h"
 #include "typeclass.h"
 #include "defaults.h"
 #include "toplev.h"
 #include "ggc.h"
+#include "intl.h"
+#include "tm_p.h"
+
+#ifndef ACCUMULATE_OUTGOING_ARGS
+#define ACCUMULATE_OUTGOING_ARGS 0
+#endif
 
-#define CEIL(x,y) (((x) + (y) - 1) / (y))
+/* Supply a default definition for PUSH_ARGS.  */
+#ifndef PUSH_ARGS
+#ifdef PUSH_ROUNDING
+#define PUSH_ARGS      !ACCUMULATE_OUTGOING_ARGS
+#else
+#define PUSH_ARGS      0
+#endif
+#endif
 
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
@@ -53,7 +67,7 @@ Boston, MA 02111-1307, USA.  */
 #ifdef PUSH_ROUNDING
 
 #if defined (STACK_GROWS_DOWNWARD) != defined (ARGS_GROW_DOWNWARD)
-#define PUSH_ARGS_REVERSED     /* If it's last to first */
+#define PUSH_ARGS_REVERSED     /* If it's last to first */
 #endif
 
 #endif
@@ -71,6 +85,15 @@ Boston, MA 02111-1307, USA.  */
 #define CASE_VECTOR_PC_RELATIVE 0
 #endif
 
+/* Hook called by safe_from_p for language-specific tree codes.  It is
+   up to the language front-end to install a hook if it has any such
+   codes that safe_from_p needs to know about.  Since same_from_p will
+   recursively explore the TREE_OPERANDs of an expression, this hook
+   should not reexamine those pieces.  This routine may recursively
+   call safe_from_p; it should always pass `0' as the TOP_P
+   parameter.  */
+int (*lang_safe_from_p) PARAMS ((rtx, tree));
+
 /* If this is nonzero, we do not bother generating VOLATILE
    around volatile memory references, and we are willing to
    output indirect addresses.  If cse is to follow, we reject
@@ -89,6 +112,9 @@ int do_preexpand_calls = 1;
    infinite recursion.  */
 static int in_check_memory_usage;
 
+/* Chain of pending expressions for PLACEHOLDER_EXPR to replace.  */
+static tree placeholder_list = 0;
+
 /* This structure is used by move_by_pieces to describe the move to
    be performed.  */
 struct move_by_pieces
@@ -97,16 +123,12 @@ struct move_by_pieces
   rtx to_addr;
   int autinc_to;
   int explicit_inc_to;
-  int to_struct;
-  int to_readonly;
   rtx from;
   rtx from_addr;
   int autinc_from;
   int explicit_inc_from;
-  int from_struct;
-  int from_readonly;
-  int len;
-  int offset;
+  unsigned HOST_WIDE_INT len;
+  HOST_WIDE_INT offset;
   int reverse;
 };
 
@@ -119,45 +141,54 @@ struct clear_by_pieces
   rtx to_addr;
   int autinc_to;
   int explicit_inc_to;
-  int to_struct;
-  int len;
-  int offset;
+  unsigned HOST_WIDE_INT len;
+  HOST_WIDE_INT offset;
   int reverse;
 };
 
 extern struct obstack permanent_obstack;
 
-static rtx get_push_address    PROTO ((int));
-
-static rtx enqueue_insn                PROTO((rtx, rtx));
-static int move_by_pieces_ninsns PROTO((unsigned int, int));
-static void move_by_pieces_1   PROTO((rtx (*) (rtx, ...), enum machine_mode,
-                                      struct move_by_pieces *));
-static void clear_by_pieces    PROTO((rtx, int, int));
-static void clear_by_pieces_1  PROTO((rtx (*) (rtx, ...),
-                                      enum machine_mode,
-                                      struct clear_by_pieces *));
-static int is_zeros_p          PROTO((tree));
-static int mostly_zeros_p      PROTO((tree));
-static void store_constructor_field PROTO((rtx, int, int, enum machine_mode,
-                                          tree, tree, int, int));
-static void store_constructor  PROTO((tree, rtx, int, int));
-static rtx store_field         PROTO((rtx, int, int, enum machine_mode, tree,
-                                      enum machine_mode, int, int,
-                                      int, int));
+static rtx get_push_address    PARAMS ((int));
+
+static rtx enqueue_insn                PARAMS ((rtx, rtx));
+static unsigned HOST_WIDE_INT move_by_pieces_ninsns
+                               PARAMS ((unsigned HOST_WIDE_INT,
+                                        unsigned int));
+static void move_by_pieces_1   PARAMS ((rtx (*) (rtx, ...), enum machine_mode,
+                                        struct move_by_pieces *));
+static void clear_by_pieces    PARAMS ((rtx, unsigned HOST_WIDE_INT,
+                                        unsigned int));
+static void clear_by_pieces_1  PARAMS ((rtx (*) (rtx, ...),
+                                        enum machine_mode,
+                                        struct clear_by_pieces *));
+static rtx get_subtarget       PARAMS ((rtx));
+static int is_zeros_p          PARAMS ((tree));
+static int mostly_zeros_p      PARAMS ((tree));
+static void store_constructor_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
+                                            HOST_WIDE_INT, enum machine_mode,
+                                            tree, tree, unsigned int, int,
+                                            int));
+static void store_constructor  PARAMS ((tree, rtx, unsigned int, int,
+                                        HOST_WIDE_INT));
+static rtx store_field         PARAMS ((rtx, HOST_WIDE_INT,
+                                        HOST_WIDE_INT, enum machine_mode,
+                                        tree, enum machine_mode, int,
+                                        unsigned int, HOST_WIDE_INT, int));
 static enum memory_use_mode
-  get_memory_usage_from_modifier PROTO((enum expand_modifier));
-static tree save_noncopied_parts PROTO((tree, tree));
-static tree init_noncopied_parts PROTO((tree, tree));
-static int safe_from_p         PROTO((rtx, tree, int));
-static int fixed_type_p                PROTO((tree));
-static rtx var_rtx             PROTO((tree));
-static rtx expand_increment    PROTO((tree, int, int));
-static void preexpand_calls    PROTO((tree));
-static void do_jump_by_parts_greater PROTO((tree, int, rtx, rtx));
-static void do_jump_by_parts_equality PROTO((tree, rtx, rtx));
-static void do_compare_and_jump        PROTO((tree, enum rtx_code, enum rtx_code, rtx, rtx));
-static rtx do_store_flag       PROTO((tree, rtx, enum machine_mode, int));
+  get_memory_usage_from_modifier PARAMS ((enum expand_modifier));
+static tree save_noncopied_parts PARAMS ((tree, tree));
+static tree init_noncopied_parts PARAMS ((tree, tree));
+static int fixed_type_p                PARAMS ((tree));
+static rtx var_rtx             PARAMS ((tree));
+static int readonly_fields_p   PARAMS ((tree));
+static rtx expand_expr_unaligned PARAMS ((tree, unsigned int *));
+static rtx expand_increment    PARAMS ((tree, int, int));
+static void preexpand_calls    PARAMS ((tree));
+static void do_jump_by_parts_greater PARAMS ((tree, int, rtx, rtx));
+static void do_jump_by_parts_equality PARAMS ((tree, rtx, rtx));
+static void do_compare_and_jump        PARAMS ((tree, enum rtx_code, enum rtx_code,
+                                        rtx, rtx));
+static rtx do_store_flag       PARAMS ((tree, rtx, enum machine_mode, int));
 
 /* Record for each mode whether we can move a register directly to or
    from an object of that mode in memory.  If we can't, we won't try
@@ -173,16 +204,16 @@ static char direct_store[NUM_MACHINE_MODES];
 #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 */
+/* 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. */
+   to perform a structure copy.  */
 #ifndef MOVE_BY_PIECES_P
-#define MOVE_BY_PIECES_P(SIZE, ALIGN) (move_by_pieces_ninsns        \
-                                       (SIZE, ALIGN) < MOVE_RATIO)
+#define MOVE_BY_PIECES_P(SIZE, ALIGN) \
+  (move_by_pieces_ninsns (SIZE, ALIGN) < MOVE_RATIO)
 #endif
 
 /* This array records the insn_code of insns to perform block moves.  */
@@ -194,7 +225,7 @@ enum insn_code clrstr_optab[NUM_MACHINE_MODES];
 /* SLOW_UNALIGNED_ACCESS is non-zero if unaligned accesses are very slow.  */
 
 #ifndef SLOW_UNALIGNED_ACCESS
-#define SLOW_UNALIGNED_ACCESS STRICT_ALIGNMENT
+#define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) STRICT_ALIGNMENT
 #endif
 \f
 /* This is run once per compilation to set up which modes can be used
@@ -279,11 +310,11 @@ init_expr_once ()
 void
 init_expr ()
 {
-  current_function->expr
-    = (struct expr_status *) xmalloc (sizeof (struct expr_status));
+  cfun->expr = (struct expr_status *) xmalloc (sizeof (struct expr_status));
 
   pending_chain = 0;
   pending_stack_adjust = 0;
+  stack_pointer_delta = 0;
   inhibit_defer_pop = 0;
   saveregs_value = 0;
   apply_args_value = 0;
@@ -311,6 +342,7 @@ free_expr_status (f)
 }
 
 /* Small sanity check that the queue is empty at the end of a function.  */
+
 void
 finish_expr_for_function ()
 {
@@ -378,9 +410,7 @@ protect_from_queue (x, modify)
          register rtx y = XEXP (x, 0);
          register rtx new = gen_rtx_MEM (GET_MODE (x), QUEUED_VAR (y));
 
-         RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (x);
          MEM_COPY_ATTRIBUTES (new, x);
-         MEM_ALIAS_SET (new) = MEM_ALIAS_SET (x);
 
          if (QUEUED_INSN (y))
            {
@@ -523,9 +553,26 @@ convert_move (to, from, unsignedp)
       return;
     }
 
+  if (VECTOR_MODE_P (to_mode) || VECTOR_MODE_P (from_mode))
+    {
+      if (GET_MODE_BITSIZE (from_mode) != GET_MODE_BITSIZE (to_mode))
+       abort ();
+
+      if (VECTOR_MODE_P (to_mode))
+       from = gen_rtx_SUBREG (to_mode, from, 0);
+      else
+       to = gen_rtx_SUBREG (from_mode, to, 0);
+
+      emit_move_insn (to, from);
+      return;
+    }
+
+  if (to_real != from_real)
+    abort ();
+
   if (to_real)
     {
-      rtx value;
+      rtx value, insns;
 
       if (GET_MODE_BITSIZE (from_mode) < GET_MODE_BITSIZE (to_mode))
        {
@@ -537,7 +584,7 @@ convert_move (to, from, unsignedp)
              return;
            }
        }
+
 #ifdef HAVE_trunchfqf2
       if (HAVE_trunchfqf2 && from_mode == HFmode && to_mode == QFmode)
        {
@@ -699,7 +746,7 @@ convert_move (to, from, unsignedp)
            case TFmode:
              libcall = extendsftf2_libfunc;
              break;
-             
+
            default:
              break;
            }
@@ -719,7 +766,7 @@ convert_move (to, from, unsignedp)
            case TFmode:
              libcall = extenddftf2_libfunc;
              break;
-             
+
            default:
              break;
            }
@@ -735,7 +782,7 @@ convert_move (to, from, unsignedp)
            case DFmode:
              libcall = truncxfdf2_libfunc;
              break;
-             
+
            default:
              break;
            }
@@ -751,12 +798,12 @@ convert_move (to, from, unsignedp)
            case DFmode:
              libcall = trunctfdf2_libfunc;
              break;
-             
+
            default:
              break;
            }
          break;
-         
+
        default:
          break;
        }
@@ -765,9 +812,13 @@ convert_move (to, from, unsignedp)
        /* This conversion is not implemented yet.  */
        abort ();
 
-      value = emit_library_call_value (libcall, NULL_RTX, 1, to_mode,
+      start_sequence ();
+      value = emit_library_call_value (libcall, NULL_RTX, LCT_CONST, to_mode,
                                       1, from, from_mode);
-      emit_move_insn (to, value);
+      insns = get_insns ();
+      end_sequence ();
+      emit_libcall_block (insns, to, value, gen_rtx_FLOAT_TRUNCATE (to_mode,
+                                                                   from));
       return;
     }
 
@@ -893,7 +944,7 @@ convert_move (to, from, unsignedp)
       return;
     }
 
-  /* Handle pointer conversion */                      /* SPEE 900220 */
+  /* Handle pointer conversion.  */                    /* SPEE 900220.  */
   if (to_mode == PQImode)
     {
       if (from_mode != QImode)
@@ -954,12 +1005,19 @@ convert_move (to, from, unsignedp)
       else
        {
 #ifdef HAVE_extendpsisi2
-         if (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 ();
        }
     }
@@ -1054,13 +1112,13 @@ convert_move (to, from, unsignedp)
              }
 
          /* No suitable intermediate mode.
-            Generate what we need with shifts. */
+            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,
+         tmp = expand_shift (RSHIFT_EXPR, to_mode, tmp, shift_amount,
                              to, unsignedp);
          if (tmp != to)
            emit_move_insn (to, tmp);
@@ -1068,7 +1126,7 @@ convert_move (to, from, unsignedp)
        }
     }
 
-  /* Support special truncate insns for certain modes.  */ 
+  /* Support special truncate insns for certain modes.  */
 
   if (from_mode == DImode && to_mode == SImode)
     {
@@ -1264,7 +1322,7 @@ convert_modes (mode, oldmode, x, unsignedp)
 
   if (GET_MODE (x) != VOIDmode)
     oldmode = GET_MODE (x);
+
   if (mode == oldmode)
     return x;
 
@@ -1336,13 +1394,12 @@ convert_modes (mode, oldmode, x, unsignedp)
   return temp;
 }
 \f
-
 /* This macro is used to determine what the largest unit size that
-   move_by_pieces can use is. */
+   move_by_pieces can use is.  */
 
 /* MOVE_MAX_PIECES is the number of bytes at a time which we can
    move efficiently, as opposed to  MOVE_MAX which is the maximum
-   number of bhytes we can move with a single instruction. */
+   number of bytes we can move with a single instruction.  */
 
 #ifndef MOVE_MAX_PIECES
 #define MOVE_MAX_PIECES   MOVE_MAX
@@ -1352,16 +1409,17 @@ convert_modes (mode, oldmode, x, unsignedp)
    from block FROM to block TO.  (These are MEM rtx's with BLKmode).
    The caller must pass FROM and TO
     through protect_from_queue before calling.
-   ALIGN (in bytes) is maximum alignment we can assume.  */
+   ALIGN is maximum alignment we can assume.  */
 
 void
 move_by_pieces (to, from, len, align)
      rtx to, from;
-     int len, align;
+     unsigned HOST_WIDE_INT len;
+     unsigned int align;
 {
   struct move_by_pieces data;
   rtx to_addr = XEXP (to, 0), from_addr = XEXP (from, 0);
-  int max_size = MOVE_MAX_PIECES + 1;
+  unsigned int max_size = MOVE_MAX_PIECES + 1;
   enum machine_mode mode = VOIDmode, tmode;
   enum insn_code icode;
 
@@ -1385,18 +1443,13 @@ move_by_pieces (to, from, len, align)
   if (data.reverse) data.offset = len;
   data.len = len;
 
-  data.to_struct = MEM_IN_STRUCT_P (to);
-  data.from_struct = MEM_IN_STRUCT_P (from);
-  data.to_readonly = RTX_UNCHANGING_P (to);
-  data.from_readonly = RTX_UNCHANGING_P (from);
-
   /* If copying requires more than two move insns,
      copy addresses to registers (to make displacements shorter)
      and use post-increment if available.  */
   if (!(data.autinc_from && data.autinc_to)
       && move_by_pieces_ninsns (len, align) > 2)
     {
-      /* Find the mode of the largest move... */
+      /* Find the mode of the largest move...  */
       for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
           tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
        if (GET_MODE_SIZE (tmode) < max_size)
@@ -1432,9 +1485,9 @@ move_by_pieces (to, from, len, align)
        data.to_addr = copy_addr_to_reg (to_addr);
     }
 
-  if (! SLOW_UNALIGNED_ACCESS
-      || align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
-    align = MOVE_MAX;
+  if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
+      || align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
+    align = MOVE_MAX * BITS_PER_UNIT;
 
   /* First move what we can in the largest integer mode, then go to
      successively smaller modes.  */
@@ -1450,9 +1503,7 @@ move_by_pieces (to, from, len, align)
        break;
 
       icode = mov_optab->handlers[(int) mode].insn_code;
-      if (icode != CODE_FOR_nothing
-         && align >= MIN (BIGGEST_ALIGNMENT / BITS_PER_UNIT,
-                          GET_MODE_SIZE (mode)))
+      if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
        move_by_pieces_1 (GEN_FCN (icode), mode, &data);
 
       max_size = GET_MODE_SIZE (mode);
@@ -1466,17 +1517,17 @@ move_by_pieces (to, from, len, align)
 /* Return number of insns required to move L bytes by pieces.
    ALIGN (in bytes) is maximum alignment we can assume.  */
 
-static int
+static unsigned HOST_WIDE_INT
 move_by_pieces_ninsns (l, align)
-     unsigned int l;
-     int align;
+     unsigned HOST_WIDE_INT l;
+     unsigned int align;
 {
-  register int n_insns = 0;
-  int max_size = MOVE_MAX + 1;
+  unsigned HOST_WIDE_INT n_insns = 0;
+  unsigned HOST_WIDE_INT max_size = MOVE_MAX + 1;
 
-  if (! SLOW_UNALIGNED_ACCESS
-      || align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
-    align = MOVE_MAX;
+  if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
+      || align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
+    align = MOVE_MAX * BITS_PER_UNIT;
 
   while (max_size > 1)
     {
@@ -1492,9 +1543,7 @@ move_by_pieces_ninsns (l, align)
        break;
 
       icode = mov_optab->handlers[(int) mode].insn_code;
-      if (icode != CODE_FOR_nothing
-         && align >= MIN (BIGGEST_ALIGNMENT / BITS_PER_UNIT,
-                          GET_MODE_SIZE (mode)))
+      if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
        n_insns += l / GET_MODE_SIZE (mode), l %= GET_MODE_SIZE (mode);
 
       max_size = GET_MODE_SIZE (mode);
@@ -1509,33 +1558,35 @@ move_by_pieces_ninsns (l, align)
 
 static void
 move_by_pieces_1 (genfun, mode, data)
-     rtx (*genfun) PROTO ((rtx, ...));
+     rtx (*genfun) PARAMS ((rtx, ...));
      enum machine_mode mode;
      struct move_by_pieces *data;
 {
-  register int size = GET_MODE_SIZE (mode);
-  register rtx to1, from1;
+  unsigned int size = GET_MODE_SIZE (mode);
+  rtx to1, from1;
 
   while (data->len >= size)
     {
-      if (data->reverse) data->offset -= size;
-
-      to1 = (data->autinc_to
-            ? gen_rtx_MEM (mode, data->to_addr)
-            : copy_rtx (change_address (data->to, mode,
-                                        plus_constant (data->to_addr,
-                                                       data->offset))));
-      MEM_IN_STRUCT_P (to1) = data->to_struct;
-      RTX_UNCHANGING_P (to1) = data->to_readonly;
-
-      from1
-       = (data->autinc_from
-          ? gen_rtx_MEM (mode, data->from_addr)
-          : copy_rtx (change_address (data->from, mode,
-                                      plus_constant (data->from_addr,
-                                                     data->offset))));
-      MEM_IN_STRUCT_P (from1) = data->from_struct;
-      RTX_UNCHANGING_P (from1) = data->from_readonly;
+      if (data->reverse)
+       data->offset -= size;
+
+      if (data->autinc_to)
+       {
+         to1 = gen_rtx_MEM (mode, data->to_addr);
+         MEM_COPY_ATTRIBUTES (to1, data->to);
+       }
+      else
+       to1 = change_address (data->to, mode,
+                             plus_constant (data->to_addr, data->offset));
+
+      if (data->autinc_from)
+       {
+         from1 = gen_rtx_MEM (mode, data->from_addr);
+         MEM_COPY_ATTRIBUTES (from1, data->from);
+       }
+      else
+       from1 = change_address (data->from, mode,
+                               plus_constant (data->from_addr, data->offset));
 
       if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
        emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size)));
@@ -1543,12 +1594,14 @@ move_by_pieces_1 (genfun, mode, data)
        emit_insn (gen_add2_insn (data->from_addr, GEN_INT (-size)));
 
       emit_insn ((*genfun) (to1, from1));
+
       if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
        emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
       if (HAVE_POST_INCREMENT && data->explicit_inc_from > 0)
        emit_insn (gen_add2_insn (data->from_addr, GEN_INT (size)));
 
-      if (! data->reverse) data->offset += size;
+      if (! data->reverse)
+       data->offset += size;
 
       data->len -= size;
     }
@@ -1561,8 +1614,7 @@ move_by_pieces_1 (genfun, mode, data)
    Both X and Y must be MEM rtx's (perhaps inside VOLATILE)
    with mode BLKmode.
    SIZE is an rtx that says how long they are.
-   ALIGN is the maximum alignment we can assume they have,
-   measured in bytes. 
+   ALIGN is the maximum alignment we can assume they have.
 
    Return the address of the new block, if memcpy is called and returns it,
    0 otherwise.  */
@@ -1571,7 +1623,7 @@ rtx
 emit_block_move (x, y, size, align)
      rtx x, y;
      rtx size;
-     int align;
+     unsigned int align;
 {
   rtx retval = 0;
 #ifdef TARGET_MEM_FUNCTIONS
@@ -1604,9 +1656,12 @@ emit_block_move (x, y, size, align)
         including more than one in the machine description unless
         the more limited one has some advantage.  */
 
-      rtx opalign = GEN_INT (align);
+      rtx opalign = GEN_INT (align / BITS_PER_UNIT);
       enum machine_mode mode;
 
+      /* Since this is a move insn, we don't care about volatility.  */
+      volatile_ok = 1;
+
       for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
           mode = GET_MODE_WIDER_MODE (mode))
        {
@@ -1642,6 +1697,7 @@ emit_block_move (x, y, size, align)
              if (pat)
                {
                  emit_insn (pat);
+                 volatile_ok = 0;
                  return 0;
                }
              else
@@ -1649,6 +1705,8 @@ emit_block_move (x, y, size, align)
            }
        }
 
+      volatile_ok = 0;
+
       /* X, Y, or SIZE may have been passed through protect_from_queue.
 
         It is unsafe to save the value generated by protect_from_queue
@@ -1662,7 +1720,7 @@ emit_block_move (x, y, size, align)
         To avoid this problem we go ahead and emit code to copy X, Y &
         SIZE into new pseudos.  We can then place those new pseudos
         into an RTL_EXPR and use them later, even after a call to
-        emit_queue. 
+        emit_queue.
 
         Note this is not strictly needed for library calls since they
         do not call emit_queue before loading their arguments.  However,
@@ -1688,7 +1746,7 @@ emit_block_move (x, y, size, align)
         examine the return value from memcpy.
 
         For targets where libcalls and normal calls have different conventions
-        for returning pointers, we could end up generating incorrect code. 
+        for returning pointers, we could end up generating incorrect code.
 
         So instead of using a libcall sequence we build up a suitable
         CALL_EXPR and expand the call in the normal fashion.  */
@@ -1704,7 +1762,7 @@ emit_block_move (x, y, size, align)
          fntype = build_pointer_type (void_type_node);
          fntype = build_function_type (fntype, NULL_TREE);
          fn = build_decl (FUNCTION_DECL, fn, fntype);
-         ggc_add_tree_root (&fn, 1);
+         ggc_add_tree_root (&fn, 1);
          DECL_EXTERNAL (fn) = 1;
          TREE_PUBLIC (fn) = 1;
          DECL_ARTIFICIAL (fn) = 1;
@@ -1713,7 +1771,7 @@ emit_block_move (x, y, size, align)
          pop_obstacks ();
        }
 
-      /* We need to make an argument list for the function call. 
+      /* We need to make an argument list for the function call.
 
         memcpy has three arguments, the first two are void * addresses and
         the last is a size_t byte count for the copy.  */
@@ -1735,7 +1793,7 @@ emit_block_move (x, y, size, align)
 
       retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
 #else
-      emit_library_call (bcopy_libfunc, 0,
+      emit_library_call (bcopy_libfunc, LCT_NORMAL,
                         VOIDmode, 3, y, Pmode, x, Pmode,
                         convert_to_mode (TYPE_MODE (integer_type_node), size,
                                          TREE_UNSIGNED (integer_type_node)),
@@ -1758,7 +1816,7 @@ move_block_to_reg (regno, x, nregs, mode)
 {
   int i;
 #ifdef HAVE_load_multiple
-  rtx pat; 
+  rtx pat;
   rtx last;
 #endif
 
@@ -1794,7 +1852,6 @@ move_block_to_reg (regno, x, nregs, mode)
    The number of registers to be filled is NREGS.  SIZE indicates the number
    of bytes in the object X.  */
 
-
 void
 move_block_from_reg (regno, x, nregs, size)
      int regno;
@@ -1804,7 +1861,7 @@ move_block_from_reg (regno, x, nregs, size)
 {
   int i;
 #ifdef HAVE_store_multiple
-  rtx pat; 
+  rtx pat;
   rtx last;
 #endif
   enum machine_mode mode;
@@ -1818,7 +1875,7 @@ move_block_from_reg (regno, x, nregs, size)
                      gen_rtx_REG (mode, regno));
       return;
     }
-    
+
   /* Blocks smaller than a word on a BYTES_BIG_ENDIAN machine must be aligned
      to the left before storing to memory.  Note that the previous test
      doesn't handle all cases (e.g. SIZE == 3).  */
@@ -1880,7 +1937,8 @@ move_block_from_reg (regno, x, nregs, size)
 void
 emit_group_load (dst, orig_src, ssize, align)
      rtx dst, orig_src;
-     int align, ssize;
+     unsigned int align;
+     int ssize;
 {
   rtx *tmps, src;
   int start, i;
@@ -1895,14 +1953,17 @@ emit_group_load (dst, orig_src, ssize, align)
   else
     start = 1;
 
-  tmps = (rtx *) alloca (sizeof(rtx) * XVECLEN (dst, 0));
+  tmps = (rtx *) alloca (sizeof (rtx) * XVECLEN (dst, 0));
 
   /* If we won't be loading directly from memory, protect the real source
      from strange tricks we might play.  */
   src = orig_src;
-  if (GET_CODE (src) != MEM)
+  if (GET_CODE (src) != MEM && ! CONSTANT_P (src))
     {
-      src = gen_reg_rtx (GET_MODE (orig_src));
+      if (GET_MODE (src) == VOIDmode)
+       src = gen_reg_rtx (GET_MODE (dst));
+      else
+       src = gen_reg_rtx (GET_MODE (orig_src));
       emit_move_insn (src, orig_src);
     }
 
@@ -1910,8 +1971,8 @@ emit_group_load (dst, orig_src, ssize, align)
   for (i = start; i < XVECLEN (dst, 0); i++)
     {
       enum machine_mode mode = GET_MODE (XEXP (XVECEXP (dst, 0, i), 0));
-      int bytepos = INTVAL (XEXP (XVECEXP (dst, 0, i), 1));
-      int bytelen = GET_MODE_SIZE (mode);
+      HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (dst, 0, i), 1));
+      unsigned int bytelen = GET_MODE_SIZE (mode);
       int shift = 0;
 
       /* Handle trailing fragments that run over the size of the struct.  */
@@ -1920,13 +1981,13 @@ emit_group_load (dst, orig_src, ssize, align)
          shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
          bytelen = ssize - bytepos;
          if (bytelen <= 0)
-           abort();
+           abort ();
        }
 
       /* Optimize the access just a bit.  */
       if (GET_CODE (src) == MEM
-         && align*BITS_PER_UNIT >= GET_MODE_ALIGNMENT (mode)
-         && bytepos*BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
+         && align >= GET_MODE_ALIGNMENT (mode)
+         && bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
          && bytelen == GET_MODE_SIZE (mode))
        {
          tmps[i] = gen_reg_rtx (mode);
@@ -1946,20 +2007,21 @@ emit_group_load (dst, orig_src, ssize, align)
          else
            abort ();
        }
+      else if ((CONSTANT_P (src)
+               && (GET_MODE (src) == VOIDmode || GET_MODE (src) == mode))
+              || (GET_CODE (src) == REG && GET_MODE (src) == mode))
+       tmps[i] = src;
       else
-       {
-         tmps[i] = extract_bit_field (src, bytelen*BITS_PER_UNIT,
-                                      bytepos*BITS_PER_UNIT, 1, NULL_RTX,
-                                      mode, mode, align, ssize);
-       }
+       tmps[i] = extract_bit_field (src, bytelen * BITS_PER_UNIT,
+                                    bytepos * BITS_PER_UNIT, 1, NULL_RTX,
+                                    mode, mode, align, ssize);
 
       if (BYTES_BIG_ENDIAN && shift)
-       {
-         expand_binop (mode, ashl_optab, tmps[i], GEN_INT (shift),
-                       tmps[i], 0, OPTAB_WIDEN);
-       }
+       expand_binop (mode, ashl_optab, tmps[i], GEN_INT (shift),
+                     tmps[i], 0, OPTAB_WIDEN);
     }
-  emit_queue();
+
+  emit_queue ();
 
   /* Copy the extracted pieces into the proper (probable) hard regs.  */
   for (i = start; i < XVECLEN (dst, 0); i++)
@@ -1973,7 +2035,8 @@ emit_group_load (dst, orig_src, ssize, align)
 void
 emit_group_store (orig_dst, src, ssize, align)
      rtx orig_dst, src;
-     int ssize, align;
+     int ssize;
+     unsigned int align;
 {
   rtx *tmps, dst;
   int start, i;
@@ -1988,7 +2051,7 @@ emit_group_store (orig_dst, src, ssize, align)
   else
     start = 1;
 
-  tmps = (rtx *) alloca (sizeof(rtx) * XVECLEN (src, 0));
+  tmps = (rtx *) alloca (sizeof (rtx) * XVECLEN (src, 0));
 
   /* Copy the (probable) hard regs into pseudos.  */
   for (i = start; i < XVECLEN (src, 0); i++)
@@ -1997,7 +2060,7 @@ emit_group_store (orig_dst, src, ssize, align)
       tmps[i] = gen_reg_rtx (GET_MODE (reg));
       emit_move_insn (tmps[i], reg);
     }
-  emit_queue();
+  emit_queue ();
 
   /* If we won't be storing directly into memory, protect the real destination
      from strange tricks we might play.  */
@@ -2027,21 +2090,13 @@ emit_group_store (orig_dst, src, ssize, align)
       /* Make life a bit easier for combine.  */
       emit_move_insn (dst, const0_rtx);
     }
-  else if (! MEM_IN_STRUCT_P (dst))
-    {
-      /* store_bit_field requires that memory operations have
-        mem_in_struct_p set; we might not.  */
-
-      dst = copy_rtx (orig_dst);
-      MEM_SET_IN_STRUCT_P (dst, 1);
-    }
 
   /* Process the pieces.  */
   for (i = start; i < XVECLEN (src, 0); i++)
     {
-      int bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1));
+      HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1));
       enum machine_mode mode = GET_MODE (tmps[i]);
-      int bytelen = GET_MODE_SIZE (mode);
+      unsigned int bytelen = GET_MODE_SIZE (mode);
 
       /* Handle trailing fragments that run over the size of the struct.  */
       if (ssize >= 0 && bytepos + bytelen > ssize)
@@ -2057,22 +2112,19 @@ emit_group_store (orig_dst, src, ssize, align)
 
       /* Optimize the access just a bit.  */
       if (GET_CODE (dst) == MEM
-         && align*BITS_PER_UNIT >= GET_MODE_ALIGNMENT (mode)
-         && bytepos*BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
+         && align >= GET_MODE_ALIGNMENT (mode)
+         && bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
          && bytelen == GET_MODE_SIZE (mode))
-       {
-         emit_move_insn (change_address (dst, mode,
-                                         plus_constant (XEXP (dst, 0),
-                                                        bytepos)),
-                         tmps[i]);
-       }
+       emit_move_insn (change_address (dst, mode,
+                                       plus_constant (XEXP (dst, 0),
+                                                      bytepos)),
+                       tmps[i]);
       else
-       {
-         store_bit_field (dst, bytelen*BITS_PER_UNIT, bytepos*BITS_PER_UNIT,
+       store_bit_field (dst, bytelen * BITS_PER_UNIT, bytepos * BITS_PER_UNIT,
                           mode, tmps[i], align, ssize);
-       }
     }
-  emit_queue();
+
+  emit_queue ();
 
   /* Copy from the pseudo into the (probable) hard reg.  */
   if (GET_CODE (dst) == REG)
@@ -2086,81 +2138,74 @@ emit_group_store (orig_dst, src, ssize, align)
    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.
-  */
+   in registers regardless of the structure's alignment.  */
 
 rtx
-copy_blkmode_from_reg(tgtblk,srcreg,type)
+copy_blkmode_from_reg (tgtblk, srcreg, type)
      rtx tgtblk;
      rtx srcreg;
      tree type;
 {
-      int bytes = int_size_in_bytes (type);
-      rtx src = NULL, dst = NULL;
-      int bitsize = MIN (TYPE_ALIGN (type), (unsigned int) BITS_PER_WORD);
-      int bitpos, xbitpos, big_endian_correction = 0;
-      
-      if (tgtblk == 0)
-       {
-         tgtblk = assign_stack_temp (BLKmode, bytes, 0);
-         MEM_SET_IN_STRUCT_P (tgtblk, AGGREGATE_TYPE_P (type));
-         preserve_temp_slots (tgtblk);
-       }
-      
-      /* This code assumes srcreg is at least a full word.  If it isn't,
-        copy it into a new pseudo which is a full word.  */
-      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 = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD)
-                                                 * BITS_PER_UNIT));
-
-      /* Copy the structure BITSIZE bites at a time.
-
-        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;
-          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
-            (the first time through).  */
-         if (xbitpos % BITS_PER_WORD == 0
-             || xbitpos == big_endian_correction)
-           src = operand_subword_force (srcreg,
-                                        xbitpos / BITS_PER_WORD, 
-                                        BLKmode);
-
-         /* We need a new destination operand each time bitpos is on
-            a word boundary.  */
-         if (bitpos % BITS_PER_WORD == 0)
-           dst = operand_subword (tgtblk, bitpos / BITS_PER_WORD, 1, BLKmode);
-             
-         /* Use xbitpos for the source extraction (right justified) and
-            xbitpos for the destination store (left justified).  */
-         store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, word_mode,
-                          extract_bit_field (src, bitsize,
-                                             xbitpos % BITS_PER_WORD, 1,
-                                             NULL_RTX, word_mode,
-                                             word_mode,
-                                             bitsize / BITS_PER_UNIT,
-                                             BITS_PER_WORD),
-                          bitsize / BITS_PER_UNIT, BITS_PER_WORD);
-       }
-      return tgtblk;
+  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;
+
+  if (tgtblk == 0)
+    {
+      tgtblk = assign_stack_temp (BLKmode, bytes, 0);
+      MEM_SET_IN_STRUCT_P (tgtblk, AGGREGATE_TYPE_P (type));
+      preserve_temp_slots (tgtblk);
+    }
+
+  /* This code assumes srcreg is at least a full word.  If it isn't,
+     copy it into a new pseudo which is a full word.  */
+  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
+      = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) * BITS_PER_UNIT));
+
+  /* Copy the structure BITSIZE bites at a time.
+
+     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;
+       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
+        (the first time through).  */
+      if (xbitpos % BITS_PER_WORD == 0
+         || xbitpos == big_endian_correction)
+       src = operand_subword_force (srcreg, xbitpos / BITS_PER_WORD, BLKmode);
+
+      /* We need a new destination operand each time bitpos is on
+        a word boundary.  */
+      if (bitpos % BITS_PER_WORD == 0)
+       dst = operand_subword (tgtblk, bitpos / BITS_PER_WORD, 1, BLKmode);
+
+      /* Use xbitpos for the source extraction (right justified) and
+        xbitpos for the destination store (left justified).  */
+      store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, word_mode,
+                      extract_bit_field (src, bitsize,
+                                         xbitpos % BITS_PER_WORD, 1,
+                                         NULL_RTX, word_mode, word_mode,
+                                         bitsize, BITS_PER_WORD),
+                      bitsize, BITS_PER_WORD);
+    }
+
+  return tgtblk;
 }
 
-
 /* Add a USE expression for REG to the (possibly empty) list pointed
    to by CALL_FUSAGE.  REG must denote a hard register.  */
 
@@ -2170,7 +2215,7 @@ use_reg (call_fusage, reg)
 {
   if (GET_CODE (reg) != REG
       || REGNO (reg) >= FIRST_PSEUDO_REGISTER)
-    abort();
+    abort ();
 
   *call_fusage
     = gen_rtx_EXPR_LIST (VOIDmode,
@@ -2218,19 +2263,19 @@ use_group_regs (call_fusage, regs)
     }
 }
 \f
-/* Generate several move instructions to clear LEN bytes of block TO.
-   (A MEM rtx with BLKmode).   The caller must pass TO through
-   protect_from_queue before calling. ALIGN (in bytes) is maximum alignment
-   we can assume.  */
+/* Generate several move instructions to clear LEN bytes of block TO.  (A MEM
+   rtx with BLKmode).  The caller must pass TO through protect_from_queue
+   before calling. ALIGN is maximum alignment we can assume.  */
 
 static void
 clear_by_pieces (to, len, align)
      rtx to;
-     int len, align;
+     unsigned HOST_WIDE_INT len;
+     unsigned int align;
 {
   struct clear_by_pieces data;
   rtx to_addr = XEXP (to, 0);
-  int max_size = MOVE_MAX_PIECES + 1;
+  unsigned HOST_WIDE_INT max_size = MOVE_MAX_PIECES + 1;
   enum machine_mode mode = VOIDmode, tmode;
   enum insn_code icode;
 
@@ -2244,18 +2289,17 @@ clear_by_pieces (to, len, align)
   data.explicit_inc_to = 0;
   data.reverse
     = (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
-  if (data.reverse) data.offset = len;
+  if (data.reverse)
+    data.offset = len;
   data.len = len;
 
-  data.to_struct = MEM_IN_STRUCT_P (to);
-
   /* If copying requires more than two move insns,
      copy addresses to registers (to make displacements shorter)
      and use post-increment if available.  */
   if (!data.autinc_to
       && move_by_pieces_ninsns (len, align) > 2)
     {
-      /* Determine the main mode we'll be using */
+      /* Determine the main mode we'll be using */
       for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
           tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
        if (GET_MODE_SIZE (tmode) < max_size)
@@ -2267,19 +2311,22 @@ clear_by_pieces (to, len, align)
          data.autinc_to = 1;
          data.explicit_inc_to = -1;
        }
-      if (USE_STORE_POST_INCREMENT (mode) && ! data.reverse && ! data.autinc_to)
+
+      if (USE_STORE_POST_INCREMENT (mode) && ! data.reverse
+         && ! data.autinc_to)
        {
          data.to_addr = copy_addr_to_reg (to_addr);
          data.autinc_to = 1;
          data.explicit_inc_to = 1;
        }
-      if (!data.autinc_to && CONSTANT_P (to_addr))
+
+      if ( !data.autinc_to && CONSTANT_P (to_addr))
        data.to_addr = copy_addr_to_reg (to_addr);
     }
 
-  if (! SLOW_UNALIGNED_ACCESS
-      || align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
-    align = MOVE_MAX;
+  if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
+      || align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
+    align = MOVE_MAX * BITS_PER_UNIT;
 
   /* First move what we can in the largest integer mode, then go to
      successively smaller modes.  */
@@ -2295,9 +2342,7 @@ clear_by_pieces (to, len, align)
        break;
 
       icode = mov_optab->handlers[(int) mode].insn_code;
-      if (icode != CODE_FOR_nothing
-         && align >= MIN (BIGGEST_ALIGNMENT / BITS_PER_UNIT,
-                          GET_MODE_SIZE (mode)))
+      if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
        clear_by_pieces_1 (GEN_FCN (icode), mode, &data);
 
       max_size = GET_MODE_SIZE (mode);
@@ -2314,40 +2359,44 @@ clear_by_pieces (to, len, align)
 
 static void
 clear_by_pieces_1 (genfun, mode, data)
-     rtx (*genfun) PROTO ((rtx, ...));
+     rtx (*genfun) PARAMS ((rtx, ...));
      enum machine_mode mode;
      struct clear_by_pieces *data;
 {
-  register int size = GET_MODE_SIZE (mode);
-  register rtx to1;
+  unsigned int size = GET_MODE_SIZE (mode);
+  rtx to1;
 
   while (data->len >= size)
     {
-      if (data->reverse) data->offset -= size;
+      if (data->reverse)
+       data->offset -= size;
 
-      to1 = (data->autinc_to
-            ? gen_rtx_MEM (mode, data->to_addr)
-            : copy_rtx (change_address (data->to, mode,
-                                        plus_constant (data->to_addr,
-                                                       data->offset))));
-      MEM_IN_STRUCT_P (to1) = data->to_struct;
+      if (data->autinc_to)
+       {
+         to1 = gen_rtx_MEM (mode, data->to_addr);
+         MEM_COPY_ATTRIBUTES (to1, data->to);
+       }
+      else
+       to1 = change_address (data->to, mode,
+                             plus_constant (data->to_addr, data->offset));
 
       if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
        emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size)));
 
       emit_insn ((*genfun) (to1, const0_rtx));
+
       if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
        emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
 
-      if (! data->reverse) data->offset += size;
+      if (! data->reverse)
+       data->offset += size;
 
       data->len -= size;
     }
 }
 \f
-/* Write zeros through the storage of OBJECT.
-   If OBJECT has BLKmode, SIZE is its length in bytes and ALIGN is
-   the maximum alignment we can is has, measured in bytes.
+/* Write zeros through the storage of OBJECT.  If OBJECT has BLKmode, SIZE is
+   its length in bytes and ALIGN is the maximum alignment we can is has.
 
    If we call a function that returns the length of the block, return it.  */
 
@@ -2355,7 +2404,7 @@ rtx
 clear_storage (object, size, align)
      rtx object;
      rtx size;
-     int align;
+     unsigned int align;
 {
 #ifdef TARGET_MEM_FUNCTIONS
   static tree fn;
@@ -2363,7 +2412,13 @@ clear_storage (object, size, align)
 #endif
   rtx retval = 0;
 
-  if (GET_MODE (object) == BLKmode)
+  /* If OBJECT is not BLKmode and SIZE is the same size as its mode,
+     just move a zero.  Otherwise, do this a piece at a time.  */
+  if (GET_MODE (object) != BLKmode
+      && GET_CODE (size) == CONST_INT
+      && GET_MODE_SIZE (GET_MODE (object)) == INTVAL (size))
+    emit_move_insn (object, CONST0_RTX (GET_MODE (object)));
+  else
     {
       object = protect_from_queue (object, 1);
       size = protect_from_queue (size, 0);
@@ -2371,14 +2426,13 @@ clear_storage (object, size, align)
       if (GET_CODE (size) == CONST_INT
          && MOVE_BY_PIECES_P (INTVAL (size), align))
        clear_by_pieces (object, INTVAL (size), align);
-
       else
        {
          /* Try the most limited insn first, because there's no point
             including more than one in the machine description unless
             the more limited one has some advantage.  */
 
-         rtx opalign = GEN_INT (align);
+         rtx opalign = GEN_INT (align / BITS_PER_UNIT);
          enum machine_mode mode;
 
          for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
@@ -2451,7 +2505,6 @@ clear_storage (object, size, align)
          size = copy_to_mode_reg (TYPE_MODE (integer_type_node), size);
 #endif
 
-
 #ifdef TARGET_MEM_FUNCTIONS
          /* It is incorrect to use the libcall calling conventions to call
             memset in this context.
@@ -2461,7 +2514,7 @@ clear_storage (object, size, align)
 
             For targets where libcalls and normal calls have different
             conventions for returning pointers, we could end up generating
-             incorrect code. 
+             incorrect code.
 
             So instead of using a libcall sequence we build up a suitable
             CALL_EXPR and expand the call in the normal fashion.  */
@@ -2486,7 +2539,7 @@ clear_storage (object, size, align)
              pop_obstacks ();
            }
 
-         /* We need to make an argument list for the function call. 
+         /* We need to make an argument list for the function call.
 
             memset has three arguments, the first is a void * addresses, the
             second a integer with the initialization value, the last is a
@@ -2497,7 +2550,7 @@ clear_storage (object, size, align)
                                          object));
          TREE_CHAIN (arg_list)
            = build_tree_list (NULL_TREE,
-                               make_tree (integer_type_node, const0_rtx));
+                              make_tree (integer_type_node, const0_rtx));
          TREE_CHAIN (TREE_CHAIN (arg_list))
            = build_tree_list (NULL_TREE, make_tree (sizetype, size));
          TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arg_list))) = NULL_TREE;
@@ -2511,14 +2564,12 @@ clear_storage (object, size, align)
 
          retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
 #else
-         emit_library_call (bzero_libfunc, 0,
+         emit_library_call (bzero_libfunc, LCT_NORMAL,
                             VOIDmode, 2, object, Pmode, size,
                             TYPE_MODE (integer_type_node));
 #endif
        }
     }
-  else
-    emit_move_insn (object, CONST0_RTX (GET_MODE (object)));
 
   return retval;
 }
@@ -2580,10 +2631,10 @@ emit_move_insn_1 (x, y)
   enum machine_mode mode = GET_MODE (x);
   enum machine_mode submode;
   enum mode_class class = GET_MODE_CLASS (mode);
-  int i;
+  unsigned int i;
 
   if (mode >= MAX_MACHINE_MODE)
-      abort ();
+    abort ();
 
   if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
     return
@@ -2613,35 +2664,94 @@ emit_move_insn_1 (x, y)
             regardless of machine's endianness.  */
 #ifdef STACK_GROWS_DOWNWARD
          emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (gen_rtx_MEM (submode, (XEXP (x, 0))),
+                    (gen_rtx_MEM (submode, XEXP (x, 0)),
                      gen_imagpart (submode, y)));
          emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (gen_rtx_MEM (submode, (XEXP (x, 0))),
+                    (gen_rtx_MEM (submode, XEXP (x, 0)),
                      gen_realpart (submode, y)));
 #else
          emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (gen_rtx_MEM (submode, (XEXP (x, 0))),
+                    (gen_rtx_MEM (submode, XEXP (x, 0)),
                      gen_realpart (submode, y)));
          emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (gen_rtx_MEM (submode, (XEXP (x, 0))),
+                    (gen_rtx_MEM (submode, XEXP (x, 0)),
                      gen_imagpart (submode, y)));
 #endif
        }
       else
        {
-         /* Show the output dies here.  This is necessary for pseudos;
+         rtx realpart_x, realpart_y;
+         rtx imagpart_x, imagpart_y;
+
+         /* If this is a complex value with each part being smaller than a
+            word, the usual calling sequence will likely pack the pieces into
+            a single register.  Unfortunately, SUBREG of hard registers only
+            deals in terms of words, so we have a problem converting input
+            arguments to the CONCAT of two registers that is used elsewhere
+            for complex values.  If this is before reload, we can copy it into
+            memory and reload.  FIXME, we should see about using extract and
+            insert on integer registers, but complex short and complex char
+            variables should be rarely used.  */
+         if (GET_MODE_BITSIZE (mode) < 2 * BITS_PER_WORD
+             && (reload_in_progress | reload_completed) == 0)
+           {
+             int packed_dest_p = (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER);
+             int packed_src_p  = (REG_P (y) && REGNO (y) < FIRST_PSEUDO_REGISTER);
+
+             if (packed_dest_p || packed_src_p)
+               {
+                 enum mode_class reg_class = ((class == MODE_COMPLEX_FLOAT)
+                                              ? MODE_FLOAT : MODE_INT);
+
+                 enum machine_mode reg_mode =
+                   mode_for_size (GET_MODE_BITSIZE (mode), reg_class, 1);
+
+                 if (reg_mode != BLKmode)
+                   {
+                     rtx mem = assign_stack_temp (reg_mode,
+                                                  GET_MODE_SIZE (mode), 0);
+
+                     rtx cmem = change_address (mem, mode, NULL_RTX);
+
+                     cfun->cannot_inline = N_("function using short complex types cannot be inline");
+
+                     if (packed_dest_p)
+                       {
+                         rtx sreg = gen_rtx_SUBREG (reg_mode, x, 0);
+                         emit_move_insn_1 (cmem, y);
+                         return emit_move_insn_1 (sreg, mem);
+                       }
+                     else
+                       {
+                         rtx sreg = gen_rtx_SUBREG (reg_mode, y, 0);
+                         emit_move_insn_1 (mem, sreg);
+                         return emit_move_insn_1 (x, cmem);
+                       }
+                   }
+               }
+           }
+
+         realpart_x = gen_realpart (submode, x);
+         realpart_y = gen_realpart (submode, y);
+         imagpart_x = gen_imagpart (submode, x);
+         imagpart_y = gen_imagpart (submode, y);
+
+         /* Show the output dies here.  This is necessary for SUBREGs
+            of pseudos since we cannot track their lifetimes correctly;
             hard regs shouldn't appear here except as return values.
             We never want to emit such a clobber after reload.  */
          if (x != y
-             && ! (reload_in_progress || reload_completed))
+             && ! (reload_in_progress || reload_completed)
+             && (GET_CODE (realpart_x) == SUBREG
+                 || GET_CODE (imagpart_x) == SUBREG))
            {
              emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
            }
 
          emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (gen_realpart (submode, x), gen_realpart (submode, y)));
+                    (realpart_x, realpart_y));
          emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (gen_imagpart (submode, x), gen_imagpart (submode, y)));
+                    (imagpart_x, imagpart_y));
        }
 
       return get_last_insn ();
@@ -2653,7 +2763,9 @@ emit_move_insn_1 (x, y)
   else if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
     {
       rtx last_insn = 0;
-      
+      rtx seq, inner;
+      int need_clobber;
+
 #ifdef PUSH_ROUNDING
 
       /* If X is a push on the stack, do the push now and replace
@@ -2664,18 +2776,31 @@ emit_move_insn_1 (x, y)
          x = change_address (x, VOIDmode, stack_pointer_rtx);
        }
 #endif
-                            
-      /* Show the output dies here.  This is necessary for pseudos;
-        hard regs shouldn't appear here except as return values.
-        We never want to emit such a clobber after reload.  */
-      if (x != y
-         && ! (reload_in_progress || reload_completed))
+
+      /* If we are in reload, see if either operand is a MEM whose address
+        is scheduled for replacement.  */
+      if (reload_in_progress && GET_CODE (x) == MEM
+         && (inner = find_replacement (&XEXP (x, 0))) != XEXP (x, 0))
        {
-         emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
+         rtx new = gen_rtx_MEM (GET_MODE (x), inner);
+
+         MEM_COPY_ATTRIBUTES (new, x);
+         x = new;
        }
+      if (reload_in_progress && GET_CODE (y) == MEM
+         && (inner = find_replacement (&XEXP (y, 0))) != XEXP (y, 0))
+       {
+         rtx new = gen_rtx_MEM (GET_MODE (y), inner);
+
+         MEM_COPY_ATTRIBUTES (new, y);
+         y = new;
+       }
+
+      start_sequence ();
 
+      need_clobber = 0;
       for (i = 0;
-          i < (GET_MODE_SIZE (mode)  + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
+          i < (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
           i++)
        {
          rtx xpart = operand_subword (x, i, 1, mode);
@@ -2695,9 +2820,27 @@ emit_move_insn_1 (x, y)
          if (xpart == 0 || ypart == 0)
            abort ();
 
+         need_clobber |= (GET_CODE (xpart) == SUBREG);
+
          last_insn = emit_move_insn (xpart, ypart);
        }
 
+      seq = gen_sequence ();
+      end_sequence ();
+
+      /* Show the output dies here.  This is necessary for SUBREGs
+        of pseudos since we cannot track their lifetimes correctly;
+        hard regs shouldn't appear here except as return values.
+        We never want to emit such a clobber after reload.  */
+      if (x != y
+         && ! (reload_in_progress || reload_completed)
+         && need_clobber != 0)
+       {
+         emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
+       }
+
+      emit_insn (seq);
+
       return last_insn;
     }
   else
@@ -2729,34 +2872,42 @@ push_block (size, extra, below)
     anti_adjust_stack (size);
   else
     {
-      rtx temp = copy_to_mode_reg (Pmode, size);
+      temp = copy_to_mode_reg (Pmode, size);
       if (extra != 0)
        temp = expand_binop (Pmode, add_optab, temp, GEN_INT (extra),
                             temp, 0, OPTAB_LIB_WIDEN);
       anti_adjust_stack (temp);
     }
 
-#if defined (STACK_GROWS_DOWNWARD) \
-    || (defined (ARGS_GROW_DOWNWARD) \
-       && !defined (ACCUMULATE_OUTGOING_ARGS))
-
-  /* Return the lowest stack address when STACK or ARGS grow downward and
-     we are not aaccumulating outgoing arguments (the c4x port uses such
-     conventions).  */
-  temp = virtual_outgoing_args_rtx;
-  if (extra != 0 && below)
-    temp = plus_constant (temp, extra);
+#ifndef STACK_GROWS_DOWNWARD
+#ifdef ARGS_GROW_DOWNWARD
+  if (!ACCUMULATE_OUTGOING_ARGS)
 #else
-  if (GET_CODE (size) == CONST_INT)
-    temp = plus_constant (virtual_outgoing_args_rtx,
-                         - INTVAL (size) - (below ? 0 : extra));
-  else if (extra != 0 && !below)
-    temp = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
-                   negate_rtx (Pmode, plus_constant (size, extra)));
-  else
-    temp = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
-                        negate_rtx (Pmode, size));
+  if (0)
+#endif
+#else
+  if (1)
 #endif
+    {
+      /* Return the lowest stack address when STACK or ARGS grow downward and
+        we are not aaccumulating outgoing arguments (the c4x port uses such
+        conventions).  */
+      temp = virtual_outgoing_args_rtx;
+      if (extra != 0 && below)
+       temp = plus_constant (temp, extra);
+    }
+  else
+    {
+      if (GET_CODE (size) == CONST_INT)
+       temp = plus_constant (virtual_outgoing_args_rtx,
+                             -INTVAL (size) - (below ? 0 : extra));
+      else if (extra != 0 && !below)
+       temp = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
+                            negate_rtx (Pmode, plus_constant (size, extra)));
+      else
+       temp = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
+                            negate_rtx (Pmode, size));
+    }
 
   return memory_address (GET_CLASS_NARROWEST_MODE (MODE_INT), temp);
 }
@@ -2772,7 +2923,7 @@ gen_push_operand ()
 
 static rtx
 get_push_address (size)
-       int size;
+     int size;
 {
   register rtx temp;
 
@@ -2793,7 +2944,7 @@ get_push_address (size)
    SIZE is an rtx for the size of data to be copied (in bytes),
    needed only if X is BLKmode.
 
-   ALIGN (in bytes) is maximum alignment we can assume.
+   ALIGN is maximum alignment we can assume.
 
    If PARTIAL and REG are both nonzero, then copy that many of the first
    words of X into registers starting with REG, and push the rest of X.
@@ -2820,18 +2971,20 @@ get_push_address (size)
 
 void
 emit_push_insn (x, mode, type, size, align, partial, reg, extra,
-               args_addr, args_so_far, reg_parm_stack_space)
+               args_addr, args_so_far, reg_parm_stack_space,
+                alignment_pad)
      register rtx x;
      enum machine_mode mode;
      tree type;
      rtx size;
-     int align;
+     unsigned int align;
      int partial;
      rtx reg;
      int extra;
      rtx args_addr;
      rtx args_so_far;
      int reg_parm_stack_space;
+     rtx alignment_pad;
 {
   rtx xinner;
   enum direction stack_direction
@@ -2861,7 +3014,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
       int used = partial * UNITS_PER_WORD;
       int offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
       int skip;
-      
+
       if (size == 0)
        abort ();
 
@@ -2885,14 +3038,15 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
         and if there is no difficulty with push insns that skip bytes
         on the stack for alignment purposes.  */
       if (args_addr == 0
+         && PUSH_ARGS
          && GET_CODE (size) == CONST_INT
          && skip == 0
          && (MOVE_BY_PIECES_P ((unsigned) INTVAL (size) - used, align))
          /* Here we avoid the case of a structure whose weak alignment
             forces many pushes of a small amount of data,
             and such small pushes do rounding that causes trouble.  */
-         && ((! SLOW_UNALIGNED_ACCESS)
-             || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT
+         && ((! SLOW_UNALIGNED_ACCESS (word_mode, align))
+             || align >= BIGGEST_ALIGNMENT
              || PUSH_ROUNDING (align) == align)
          && PUSH_ROUNDING (INTVAL (size)) == INTVAL (size))
        {
@@ -2903,25 +3057,26 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
              && where_pad != none && where_pad != stack_direction)
            anti_adjust_stack (GEN_INT (extra));
 
+         stack_pointer_delta += INTVAL (size) - used;
          move_by_pieces (gen_rtx_MEM (BLKmode, gen_push_operand ()), xinner,
                          INTVAL (size) - used, align);
 
          if (current_function_check_memory_usage && ! in_check_memory_usage)
            {
              rtx temp;
-             
+
              in_check_memory_usage = 1;
-             temp = get_push_address (INTVAL(size) - used);
+             temp = get_push_address (INTVAL (size) - used);
              if (GET_CODE (x) == MEM && type && AGGREGATE_TYPE_P (type))
-               emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
-                                  temp, Pmode,
-                                  XEXP (xinner, 0), Pmode,
-                                  GEN_INT (INTVAL(size) - used),
+               emit_library_call (chkr_copy_bitmap_libfunc,
+                                  LCT_CONST_MAKE_BLOCK, VOIDmode, 3, temp,
+                                  Pmode, XEXP (xinner, 0), Pmode,
+                                  GEN_INT (INTVAL (size) - used),
                                   TYPE_MODE (sizetype));
              else
-               emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
-                                  temp, Pmode,
-                                  GEN_INT (INTVAL(size) - used),
+               emit_library_call (chkr_set_right_libfunc,
+                                  LCT_CONST_MAKE_BLOCK, VOIDmode, 3, temp,
+                                  Pmode, GEN_INT (INTVAL (size) - used),
                                   TYPE_MODE (sizetype),
                                   GEN_INT (MEMORY_USE_RW),
                                   TYPE_MODE (integer_type_node));
@@ -2929,8 +3084,10 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
            }
        }
       else
-#endif /* PUSH_ROUNDING */
+#endif /* PUSH_ROUNDING  */
        {
+         rtx target;
+
          /* Otherwise make space on the stack and copy the data
             to the address of that space.  */
 
@@ -2965,17 +3122,17 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
                                                  skip));
          if (current_function_check_memory_usage && ! in_check_memory_usage)
            {
-             rtx target;
-             
              in_check_memory_usage = 1;
              target = copy_to_reg (temp);
              if (GET_CODE (x) == MEM && type && AGGREGATE_TYPE_P (type))
-               emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
+               emit_library_call (chkr_copy_bitmap_libfunc,
+                                  LCT_CONST_MAKE_BLOCK, VOIDmode, 3,
                                   target, Pmode,
                                   XEXP (xinner, 0), Pmode,
                                   size, TYPE_MODE (sizetype));
              else
-               emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+               emit_library_call (chkr_set_right_libfunc,
+                                  LCT_CONST_MAKE_BLOCK, VOIDmode, 3,
                                   target, Pmode,
                                   size, TYPE_MODE (sizetype),
                                   GEN_INT (MEMORY_USE_RW),
@@ -2983,19 +3140,29 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
              in_check_memory_usage = 0;
            }
 
+         target = gen_rtx_MEM (BLKmode, temp);
+
+         if (type != 0)
+           {
+             set_mem_attributes (target, type, 1);
+             /* Function incoming arguments may overlap with sibling call
+                outgoing arguments and we cannot allow reordering of reads
+                from function arguments with stores to outgoing arguments
+                of sibling calls.  */
+             MEM_ALIAS_SET (target) = 0;
+           }
+
          /* TEMP is the address of the block.  Copy the data there.  */
          if (GET_CODE (size) == CONST_INT
-             && (MOVE_BY_PIECES_P ((unsigned) INTVAL (size), align)))
+             && MOVE_BY_PIECES_P ((unsigned) INTVAL (size), align))
            {
-             move_by_pieces (gen_rtx_MEM (BLKmode, temp), xinner,
-                             INTVAL (size), align);
+             move_by_pieces (target, xinner, INTVAL (size), align);
              goto ret;
            }
          else
            {
-             rtx opalign = GEN_INT (align);
+             rtx opalign = GEN_INT (align / BITS_PER_UNIT);
              enum machine_mode mode;
-             rtx target = gen_rtx_MEM (BLKmode, temp);
 
              for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
                   mode != VOIDmode;
@@ -3037,27 +3204,28 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
                }
            }
 
-#ifndef ACCUMULATE_OUTGOING_ARGS
-         /* If the source is referenced relative to the stack pointer,
-            copy it to another register to stabilize it.  We do not need
-            to do this if we know that we won't be changing sp.  */
+         if (!ACCUMULATE_OUTGOING_ARGS)
+           {
+             /* If the source is referenced relative to the stack pointer,
+                copy it to another register to stabilize it.  We do not need
+                to do this if we know that we won't be changing sp.  */
 
-         if (reg_mentioned_p (virtual_stack_dynamic_rtx, temp)
-             || reg_mentioned_p (virtual_outgoing_args_rtx, temp))
-           temp = copy_to_reg (temp);
-#endif
+             if (reg_mentioned_p (virtual_stack_dynamic_rtx, temp)
+                 || reg_mentioned_p (virtual_outgoing_args_rtx, temp))
+               temp = copy_to_reg (temp);
+           }
 
          /* Make inhibit_defer_pop nonzero around the library call
             to force it to pop the bcopy-arguments right away.  */
          NO_DEFER_POP;
 #ifdef TARGET_MEM_FUNCTIONS
-         emit_library_call (memcpy_libfunc, 0,
+         emit_library_call (memcpy_libfunc, LCT_NORMAL,
                             VOIDmode, 3, temp, Pmode, XEXP (xinner, 0), Pmode,
                             convert_to_mode (TYPE_MODE (sizetype),
                                              size, TREE_UNSIGNED (sizetype)),
                             TYPE_MODE (sizetype));
 #else
-         emit_library_call (bcopy_libfunc, 0,
+         emit_library_call (bcopy_libfunc, LCT_NORMAL,
                             VOIDmode, 3, XEXP (xinner, 0), Pmode, temp, Pmode,
                             convert_to_mode (TYPE_MODE (integer_type_node),
                                              size,
@@ -3126,12 +3294,13 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
                          0, args_addr,
                          GEN_INT (args_offset + ((i - not_stack + skip)
                                                  * UNITS_PER_WORD)),
-                         reg_parm_stack_space);
+                         reg_parm_stack_space, alignment_pad);
     }
   else
     {
       rtx addr;
       rtx target = NULL_RTX;
+      rtx dest;
 
       /* Push padding now if padding above and stack grows down,
         or if padding below and stack grows up.
@@ -3141,23 +3310,37 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
        anti_adjust_stack (GEN_INT (extra));
 
 #ifdef PUSH_ROUNDING
-      if (args_addr == 0)
-       addr = gen_push_operand ();
+      if (args_addr == 0 && PUSH_ARGS)
+       {
+         addr = gen_push_operand ();
+         stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
+       }
       else
 #endif
        {
          if (GET_CODE (args_so_far) == CONST_INT)
            addr
              = memory_address (mode,
-                               plus_constant (args_addr, 
+                               plus_constant (args_addr,
                                               INTVAL (args_so_far)));
-          else
+         else
            addr = memory_address (mode, gen_rtx_PLUS (Pmode, args_addr,
                                                       args_so_far));
          target = addr;
        }
 
-      emit_move_insn (gen_rtx_MEM (mode, addr), x);
+      dest = gen_rtx_MEM (mode, addr);
+      if (type != 0)
+       {
+         set_mem_attributes (dest, type, 1);
+         /* Function incoming arguments may overlap with sibling call
+            outgoing arguments and we cannot allow reordering of reads
+            from function arguments with stores to outgoing arguments
+            of sibling calls.  */
+         MEM_ALIAS_SET (dest) = 0;
+       }
+
+      emit_move_insn (dest, x);
 
       if (current_function_check_memory_usage && ! in_check_memory_usage)
        {
@@ -3166,15 +3349,15 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
            target = get_push_address (GET_MODE_SIZE (mode));
 
          if (GET_CODE (x) == MEM && type && AGGREGATE_TYPE_P (type))
-           emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
-                              target, Pmode,
-                              XEXP (x, 0), Pmode,
+           emit_library_call (chkr_copy_bitmap_libfunc,
+                              LCT_CONST_MAKE_BLOCK, VOIDmode, 3, target,
+                              Pmode, XEXP (x, 0), Pmode,
                               GEN_INT (GET_MODE_SIZE (mode)),
                               TYPE_MODE (sizetype));
          else
-           emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
-                              target, Pmode,
-                              GEN_INT (GET_MODE_SIZE (mode)),
+           emit_library_call (chkr_set_right_libfunc,
+                              LCT_CONST_MAKE_BLOCK, VOIDmode, 3, target,
+                              Pmode, GEN_INT (GET_MODE_SIZE (mode)),
                               TYPE_MODE (sizetype),
                               GEN_INT (MEMORY_USE_RW),
                               TYPE_MODE (integer_type_node));
@@ -3198,8 +3381,31 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
 
   if (extra && args_addr == 0 && where_pad == stack_direction)
     anti_adjust_stack (GEN_INT (extra));
+
+  if (alignment_pad && args_addr == 0)
+    anti_adjust_stack (alignment_pad);
 }
 \f
+/* Return X if X can be used as a subtarget in a sequence of arithmetic
+   operations.  */
+
+static rtx
+get_subtarget (x)
+     rtx x;
+{
+  return ((x == 0
+          /* Only registers can be subtargets.  */
+          || GET_CODE (x) != REG
+          /* If the register is readonly, it can't be set more than once.  */
+          || RTX_UNCHANGING_P (x)
+          /* Don't use hard regs to avoid extending their life.  */
+          || REGNO (x) < FIRST_PSEUDO_REGISTER
+          /* Avoid subtargets inside loops,
+             since they hide some invariant expressions.  */
+          || preserve_subexpressions_p ())
+         ? 0 : x);
+}
+
 /* Expand an assignment that stores the value of FROM into TO.
    If WANT_VALUE is nonzero, return an rtx for the value of TO.
    (This may contain a QUEUED rtx;
@@ -3238,13 +3444,12 @@ expand_assignment (to, from, want_value, suggest_reg)
       || TREE_CODE (to) == ARRAY_REF)
     {
       enum machine_mode mode1;
-      int bitsize;
-      int bitpos;
+      HOST_WIDE_INT bitsize, bitpos;
       tree offset;
       int unsignedp;
       int volatilep = 0;
       tree tem;
-      int alignment;
+      unsigned int alignment;
 
       push_temp_slots ();
       tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
@@ -3279,9 +3484,9 @@ expand_assignment (to, from, want_value, suggest_reg)
              && GET_MODE (to_rtx) == BLKmode
              && GET_MODE (XEXP (to_rtx, 0)) != VOIDmode
              && bitsize
-             && (bitpos % bitsize) == 0 
+             && (bitpos % bitsize) == 0
              && (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
-             && (alignment * BITS_PER_UNIT) == GET_MODE_ALIGNMENT (mode1))
+             && alignment == GET_MODE_ALIGNMENT (mode1))
            {
              rtx temp = change_address (to_rtx, mode1,
                                         plus_constant (XEXP (to_rtx, 0),
@@ -3351,35 +3556,58 @@ expand_assignment (to, from, want_value, suggest_reg)
          size *= GET_MODE_SIZE (best_mode);
 
          /* Check the access right of the pointer.  */
+         in_check_memory_usage = 1;
          if (size)
-           emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
-                              to_addr, Pmode,
+           emit_library_call (chkr_check_addr_libfunc, LCT_CONST_MAKE_BLOCK,
+                              VOIDmode, 3, to_addr, Pmode,
                               GEN_INT (size), TYPE_MODE (sizetype),
                               GEN_INT (MEMORY_USE_WO),
                               TYPE_MODE (integer_type_node));
+         in_check_memory_usage = 0;
        }
 
-      result = store_field (to_rtx, bitsize, bitpos, mode1, from,
-                           (want_value
-                            /* Spurious cast makes HPUX compiler happy.  */
-                            ? (enum machine_mode) TYPE_MODE (TREE_TYPE (to))
-                            : VOIDmode),
-                           unsignedp,
-                           /* Required alignment of containing datum.  */
-                           alignment,
-                           int_size_in_bytes (TREE_TYPE (tem)),
-                           get_alias_set (to));
-      preserve_temp_slots (result);
-      free_temp_slots ();
-      pop_temp_slots ();
+      /* If this is a varying-length object, we must get the address of
+        the source and do an explicit block move.  */
+      if (bitsize < 0)
+       {
+         unsigned int from_align;
+         rtx from_rtx = expand_expr_unaligned (from, &from_align);
+         rtx inner_to_rtx
+           = change_address (to_rtx, VOIDmode,
+                             plus_constant (XEXP (to_rtx, 0),
+                                            bitpos / BITS_PER_UNIT));
+
+         emit_block_move (inner_to_rtx, from_rtx, expr_size (from),
+                          MIN (alignment, from_align));
+         free_temp_slots ();
+         pop_temp_slots ();
+         return to_rtx;
+       }
+      else
+       {
+         result = store_field (to_rtx, bitsize, bitpos, mode1, from,
+                               (want_value
+                                /* Spurious cast for HPUX compiler.  */
+                                ? ((enum machine_mode)
+                                   TYPE_MODE (TREE_TYPE (to)))
+                                : VOIDmode),
+                               unsignedp,
+                               alignment,
+                               int_size_in_bytes (TREE_TYPE (tem)),
+                               get_alias_set (to));
 
-      /* If the value is meaningful, convert RESULT to the proper mode.
-        Otherwise, return nothing.  */
-      return (want_value ? convert_modes (TYPE_MODE (TREE_TYPE (to)),
-                                         TYPE_MODE (TREE_TYPE (from)),
-                                         result,
-                                         TREE_UNSIGNED (TREE_TYPE (to)))
-             : NULL_RTX);
+         preserve_temp_slots (result);
+         free_temp_slots ();
+         pop_temp_slots ();
+
+         /* If the value is meaningful, convert RESULT to the proper mode.
+            Otherwise, return nothing.  */
+         return (want_value ? convert_modes (TYPE_MODE (TREE_TYPE (to)),
+                                             TYPE_MODE (TREE_TYPE (from)),
+                                             result,
+                                             TREE_UNSIGNED (TREE_TYPE (to)))
+                 : NULL_RTX);
+       }
     }
 
   /* If the rhs is a function call and its value is not an aggregate,
@@ -3388,13 +3616,14 @@ expand_assignment (to, from, want_value, suggest_reg)
      val = setjmp (buf) on machines where reference to val
      requires loading up part of an address in a separate insn.
 
-     Don't do this if TO is a VAR_DECL whose DECL_RTL is REG 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.  */
+     Don't do this if TO is a VAR_DECL or PARM_DECL whose DECL_RTL is REG
+     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)
       && TREE_CODE (TYPE_SIZE (TREE_TYPE (from))) == INTEGER_CST
-      && ! (TREE_CODE (to) == VAR_DECL && GET_CODE (DECL_RTL (to)) == REG))
+      && ! ((TREE_CODE (to) == VAR_DECL || TREE_CODE (to) == PARM_DECL)
+           && GET_CODE (DECL_RTL (to)) == REG))
     {
       rtx value;
 
@@ -3407,10 +3636,10 @@ expand_assignment (to, from, want_value, suggest_reg)
         The Irix 6 ABI has examples of this.  */
       if (GET_CODE (to_rtx) == PARALLEL)
        emit_group_load (to_rtx, value, int_size_in_bytes (TREE_TYPE (from)),
-                        TYPE_ALIGN (TREE_TYPE (from)) / BITS_PER_UNIT);
+                        TYPE_ALIGN (TREE_TYPE (from)));
       else if (GET_MODE (to_rtx) == BLKmode)
        emit_block_move (to_rtx, value, expr_size (from),
-                        TYPE_ALIGN (TREE_TYPE (from)) / BITS_PER_UNIT);
+                        TYPE_ALIGN (TREE_TYPE (from)));
       else
        {
 #ifdef POINTERS_EXTEND_UNSIGNED
@@ -3437,13 +3666,20 @@ expand_assignment (to, from, want_value, suggest_reg)
     }
 
   /* Don't move directly into a return register.  */
-  if (TREE_CODE (to) == RESULT_DECL && GET_CODE (to_rtx) == REG)
+  if (TREE_CODE (to) == RESULT_DECL
+      && (GET_CODE (to_rtx) == REG || GET_CODE (to_rtx) == PARALLEL))
     {
       rtx temp;
 
       push_temp_slots ();
       temp = expand_expr (from, 0, GET_MODE (to_rtx), 0);
-      emit_move_insn (to_rtx, temp);
+
+      if (GET_CODE (to_rtx) == PARALLEL)
+       emit_group_load (to_rtx, temp, int_size_in_bytes (TREE_TYPE (from)),
+                        TYPE_ALIGN (TREE_TYPE (from)));
+      else
+       emit_move_insn (to_rtx, temp);
+
       preserve_temp_slots (to_rtx);
       free_temp_slots ();
       pop_temp_slots ();
@@ -3466,22 +3702,22 @@ expand_assignment (to, from, want_value, suggest_reg)
 
       /* Copy the rights of the bitmap.  */
       if (current_function_check_memory_usage)
-       emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
-                          XEXP (to_rtx, 0), Pmode,
+       emit_library_call (chkr_copy_bitmap_libfunc, LCT_CONST_MAKE_BLOCK,
+                          VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
                           XEXP (from_rtx, 0), Pmode,
                           convert_to_mode (TYPE_MODE (sizetype),
                                            size, TREE_UNSIGNED (sizetype)),
                           TYPE_MODE (sizetype));
 
 #ifdef TARGET_MEM_FUNCTIONS
-      emit_library_call (memcpy_libfunc, 0,
+      emit_library_call (memcpy_libfunc, LCT_NORMAL,
                         VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
                         XEXP (from_rtx, 0), Pmode,
                         convert_to_mode (TYPE_MODE (sizetype),
                                          size, TREE_UNSIGNED (sizetype)),
                         TYPE_MODE (sizetype));
 #else
-      emit_library_call (bcopy_libfunc, 0,
+      emit_library_call (bcopy_libfunc, LCT_NORMAL,
                         VOIDmode, 3, XEXP (from_rtx, 0), Pmode,
                         XEXP (to_rtx, 0), Pmode,
                         convert_to_mode (TYPE_MODE (integer_type_node),
@@ -3636,7 +3872,7 @@ store_expr (exp, target, want_value)
                                        SUBREG_PROMOTED_UNSIGNED_P (target)),
                         exp);
        }
-        
+
       temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
 
       /* If TEMP is a volatile MEM and we want a result value, make
@@ -3704,17 +3940,19 @@ store_expr (exp, target, want_value)
       && GET_CODE (target) == MEM
       && AGGREGATE_TYPE_P (TREE_TYPE (exp)))
     {
+      in_check_memory_usage = 1;
       if (GET_CODE (temp) == MEM)
-        emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
-                          XEXP (target, 0), Pmode,
+       emit_library_call (chkr_copy_bitmap_libfunc, LCT_CONST_MAKE_BLOCK,
+                          VOIDmode, 3, XEXP (target, 0), Pmode,
                           XEXP (temp, 0), Pmode,
                           expr_size (exp), TYPE_MODE (sizetype));
       else
-        emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
-                          XEXP (target, 0), Pmode, 
+       emit_library_call (chkr_check_addr_libfunc, LCT_CONST_MAKE_BLOCK,
+                          VOIDmode, 3, XEXP (target, 0), Pmode,
                           expr_size (exp), TYPE_MODE (sizetype),
-                          GEN_INT (MEMORY_USE_WO), 
+                          GEN_INT (MEMORY_USE_WO),
                           TYPE_MODE (integer_type_node));
+      in_check_memory_usage = 0;
     }
 
   /* If value was not generated in the target, store it there.
@@ -3766,23 +4004,22 @@ store_expr (exp, target, want_value)
          size = expr_size (exp);
          if (GET_CODE (size) == CONST_INT
              && INTVAL (size) < TREE_STRING_LENGTH (exp))
-           emit_block_move (target, temp, size,
-                            TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
+           emit_block_move (target, temp, size, TYPE_ALIGN (TREE_TYPE (exp)));
          else
            {
              /* Compute the size of the data to copy from the string.  */
              tree copy_size
                = size_binop (MIN_EXPR,
                              make_tree (sizetype, size),
-                             convert (sizetype,
-                                      build_int_2 (TREE_STRING_LENGTH (exp), 0)));
+                             size_int (TREE_STRING_LENGTH (exp)));
+             unsigned int align = TYPE_ALIGN (TREE_TYPE (exp));
              rtx copy_size_rtx = expand_expr (copy_size, NULL_RTX,
                                               VOIDmode, 0);
              rtx label = 0;
 
              /* Copy that much.  */
              emit_block_move (target, temp, copy_size_rtx,
-                              TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
+                              TYPE_ALIGN (TREE_TYPE (exp)));
 
              /* Figure out how much is left in TARGET that we have to clear.
                 Do all calculations in ptr_mode.  */
@@ -3793,7 +4030,10 @@ store_expr (exp, target, want_value)
              if (GET_CODE (copy_size_rtx) == CONST_INT)
                {
                  addr = plus_constant (addr, TREE_STRING_LENGTH (exp));
-                 size = plus_constant (size, - TREE_STRING_LENGTH (exp));
+                 size = plus_constant (size, -TREE_STRING_LENGTH (exp));
+                 align = MIN (align, (BITS_PER_UNIT
+                                      * (INTVAL (copy_size_rtx)
+                                         & - INTVAL (copy_size_rtx))));
                }
              else
                {
@@ -3806,36 +4046,30 @@ store_expr (exp, target, want_value)
                                       copy_size_rtx, NULL_RTX, 0,
                                       OPTAB_LIB_WIDEN);
 
+                 align = BITS_PER_UNIT;
                  label = gen_label_rtx ();
                  emit_cmp_and_jump_insns (size, const0_rtx, LT, NULL_RTX,
                                           GET_MODE (size), 0, 0, label);
                }
+             align = MIN (align, expr_align (copy_size));
 
              if (size != const0_rtx)
                {
+                 rtx dest = gen_rtx_MEM (BLKmode, addr);
+
+                 MEM_COPY_ATTRIBUTES (dest, target);
+
                  /* Be sure we can write on ADDR.  */
+                 in_check_memory_usage = 1;
                  if (current_function_check_memory_usage)
-                   emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
+                   emit_library_call (chkr_check_addr_libfunc,
+                                      LCT_CONST_MAKE_BLOCK, VOIDmode, 3,
                                       addr, Pmode,
                                       size, TYPE_MODE (sizetype),
-                                      GEN_INT (MEMORY_USE_WO), 
+                                      GEN_INT (MEMORY_USE_WO),
                                       TYPE_MODE (integer_type_node));
-#ifdef TARGET_MEM_FUNCTIONS
-                 emit_library_call (memset_libfunc, 0, VOIDmode, 3,
-                                    addr, ptr_mode,
-                                    const0_rtx, TYPE_MODE (integer_type_node),
-                                    convert_to_mode (TYPE_MODE (sizetype),
-                                                     size,
-                                                     TREE_UNSIGNED (sizetype)),
-                                    TYPE_MODE (sizetype));
-#else
-                 emit_library_call (bzero_libfunc, 0, VOIDmode, 2,
-                                    addr, ptr_mode,
-                                    convert_to_mode (TYPE_MODE (integer_type_node),
-                                                     size,
-                                                     TREE_UNSIGNED (integer_type_node)),
-                                    TYPE_MODE (integer_type_node));
-#endif
+                 in_check_memory_usage = 0;
+                 clear_storage (dest, size, align);
                }
 
              if (label)
@@ -3846,10 +4080,10 @@ store_expr (exp, target, want_value)
         The Irix 6 ABI has examples of this.  */
       else if (GET_CODE (target) == PARALLEL)
        emit_group_load (target, temp, int_size_in_bytes (TREE_TYPE (exp)),
-                        TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
+                        TYPE_ALIGN (TREE_TYPE (exp)));
       else if (GET_MODE (temp) == BLKmode)
        emit_block_move (target, temp, expr_size (exp),
-                        TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
+                        TYPE_ALIGN (TREE_TYPE (exp)));
       else
        emit_move_insn (target, temp);
     }
@@ -3868,7 +4102,7 @@ store_expr (exp, target, want_value)
           && ! (GET_CODE (target) == REG
                 && REGNO (target) < FIRST_PSEUDO_REGISTER))
     return copy_to_reg (target);
-  
+
   else
     return target;
 }
@@ -3889,7 +4123,7 @@ is_zeros_p (exp)
       return is_zeros_p (TREE_OPERAND (exp, 0));
 
     case INTEGER_CST:
-      return TREE_INT_CST_LOW (exp) == 0 && TREE_INT_CST_HIGH (exp) == 0;
+      return integer_zerop (exp);
 
     case COMPLEX_CST:
       return
@@ -3906,7 +4140,7 @@ is_zeros_p (exp)
          return 0;
 
       return 1;
-      
+
     default:
       return 0;
     }
@@ -3949,6 +4183,7 @@ mostly_zeros_p (exp)
    TARGET, BITSIZE, BITPOS, MODE, EXP are as for store_field.
    TYPE is the type of the CONSTRUCTOR, not the element type.
    ALIGN and CLEARED are as for store_constructor.
+   ALIAS_SET is the alias set to use for any stores.
 
    This provides a recursive shortcut back to store_constructor when it isn't
    necessary to go through store_field.  This is so that we can pass through
@@ -3957,13 +4192,15 @@ mostly_zeros_p (exp)
 
 static void
 store_constructor_field (target, bitsize, bitpos,
-                        mode, exp, type, align, cleared)
+                        mode, exp, type, align, cleared, alias_set)
      rtx target;
-     int bitsize, bitpos;
+     unsigned HOST_WIDE_INT bitsize;
+     HOST_WIDE_INT bitpos;
      enum machine_mode mode;
      tree exp, type;
-     int align;
+     unsigned int align;
      int cleared;
+     int alias_set;
 {
   if (TREE_CODE (exp) == CONSTRUCTOR
       && bitpos % BITS_PER_UNIT == 0
@@ -3973,32 +4210,42 @@ store_constructor_field (target, bitsize, bitpos,
       && (bitpos == 0 || GET_CODE (target) == MEM))
     {
       if (bitpos != 0)
-       target = change_address (target, VOIDmode,
-                                plus_constant (XEXP (target, 0),
-                                               bitpos / BITS_PER_UNIT));
-      store_constructor (exp, target, align, cleared);
+       target
+         = change_address (target,
+                           GET_MODE (target) == BLKmode
+                           || 0 != (bitpos
+                                    % GET_MODE_ALIGNMENT (GET_MODE (target)))
+                           ? BLKmode : VOIDmode,
+                           plus_constant (XEXP (target, 0),
+                                          bitpos / BITS_PER_UNIT));
+
+      MEM_ALIAS_SET (target) = alias_set;
+      store_constructor (exp, target, align, cleared, bitsize / BITS_PER_UNIT);
     }
   else
-    store_field (target, bitsize, bitpos, mode, exp, VOIDmode, 0, 
-                (align + BITS_PER_UNIT - 1) / BITS_PER_UNIT,
-                int_size_in_bytes (type), cleared);
+    store_field (target, bitsize, bitpos, mode, exp, VOIDmode, 0, align,
+                int_size_in_bytes (type), alias_set);
 }
 
 /* Store the value of constructor EXP into the rtx TARGET.
    TARGET is either a REG or a MEM.
-   ALIGN is the maximum known alignment for TARGET, in bits.
-   CLEARED is true if TARGET is known to have been zero'd.  */
+   ALIGN is the maximum known alignment for TARGET.
+   CLEARED is true if TARGET is known to have been zero'd.
+   SIZE is the number of bytes of TARGET we are allowed to modify: this
+   may not be the same as the size of EXP if we are assigning to a field
+   which has been packed to exclude padding bits.  */
 
 static void
-store_constructor (exp, target, align, cleared)
+store_constructor (exp, target, align, cleared, size)
      tree exp;
      rtx target;
-     int align;
+     unsigned int align;
      int cleared;
+     HOST_WIDE_INT size;
 {
   tree type = TREE_TYPE (exp);
 #ifdef WORD_REGISTER_OPERATIONS
-  rtx exp_size = expr_size (exp);
+  HOST_WIDE_INT exp_size = int_size_in_bytes (type);
 #endif
 
   /* We know our target cannot conflict, since safe_from_p has been called.  */
@@ -4009,7 +4256,7 @@ store_constructor (exp, target, align, cleared)
   if (GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER)
     {
       rtx temp = gen_reg_rtx (GET_MODE (target));
-      store_constructor (exp, temp, 0);
+      store_constructor (exp, temp, align, cleared, size);
       emit_move_insn (target, temp);
       return;
     }
@@ -4021,9 +4268,16 @@ store_constructor (exp, target, align, cleared)
       register tree elt;
 
       /* Inform later passes that the whole union value is dead.  */
-      if (TREE_CODE (type) == UNION_TYPE
-         || TREE_CODE (type) == QUAL_UNION_TYPE)
-       emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
+      if ((TREE_CODE (type) == UNION_TYPE
+          || TREE_CODE (type) == QUAL_UNION_TYPE)
+         && ! cleared)
+       {
+         emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
+
+         /* If the constructor is empty, clear the union.  */
+         if (! CONSTRUCTOR_ELTS (exp)  && ! cleared)
+           clear_storage (target, expr_size (exp), TYPE_ALIGN (type));
+       }
 
       /* If we are building a static constructor into a register,
         set the initial value as zero so we can fold the value into
@@ -4040,18 +4294,22 @@ store_constructor (exp, target, align, cleared)
 
       /* If the constructor has fewer fields than the structure
         or if we are initializing the structure to mostly zeros,
-        clear the whole structure first.  */
-      else if ((list_length (CONSTRUCTOR_ELTS (exp))
-               != list_length (TYPE_FIELDS (type)))
-              || mostly_zeros_p (exp))
+        clear the whole structure first.  Don't do this is TARGET is
+        register whose mode size isn't equal to SIZE since clear_storage
+        can't handle this case.  */
+      else if (size > 0
+              && ((list_length (CONSTRUCTOR_ELTS (exp))
+                   != fields_length (type))
+                  || mostly_zeros_p (exp))
+              && (GET_CODE (target) != REG
+                  || GET_MODE_SIZE (GET_MODE (target)) == size))
        {
          if (! cleared)
-           clear_storage (target, expr_size (exp),
-                          (align + BITS_PER_UNIT - 1) / BITS_PER_UNIT);
+           clear_storage (target, GEN_INT (size), align);
 
          cleared = 1;
        }
-      else
+      else if (! cleared)
        /* Inform later passes that the old value is dead.  */
        emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
 
@@ -4065,10 +4323,10 @@ store_constructor (exp, target, align, cleared)
          tree value = TREE_VALUE (elt);
 #endif
          register enum machine_mode mode;
-         int bitsize;
-         int bitpos = 0;
+         HOST_WIDE_INT bitsize;
+         HOST_WIDE_INT bitpos = 0;
          int unsignedp;
-         tree pos, constant = 0, offset = 0;
+         tree offset;
          rtx to_rtx = target;
 
          /* Just ignore missing fields.
@@ -4080,23 +4338,25 @@ store_constructor (exp, target, align, cleared)
          if (cleared && is_zeros_p (TREE_VALUE (elt)))
            continue;
 
-         bitsize = TREE_INT_CST_LOW (DECL_SIZE (field));
+         if (host_integerp (DECL_SIZE (field), 1))
+           bitsize = tree_low_cst (DECL_SIZE (field), 1);
+         else
+           bitsize = -1;
+
          unsignedp = TREE_UNSIGNED (field);
          mode = DECL_MODE (field);
          if (DECL_BIT_FIELD (field))
            mode = VOIDmode;
 
-         pos = DECL_FIELD_BITPOS (field);
-         if (TREE_CODE (pos) == INTEGER_CST)
-           constant = pos;
-         else if (TREE_CODE (pos) == PLUS_EXPR
-                  && TREE_CODE (TREE_OPERAND (pos, 1)) == INTEGER_CST)
-           constant = TREE_OPERAND (pos, 1), offset = TREE_OPERAND (pos, 0);
+         offset = DECL_FIELD_OFFSET (field);
+         if (host_integerp (offset, 0)
+             && host_integerp (bit_position (field), 0))
+           {
+             bitpos = int_bit_position (field);
+             offset = 0;
+           }
          else
-           offset = pos;
-
-         if (constant)
-           bitpos = TREE_INT_CST_LOW (constant);
+           bitpos = tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 0);
 
          if (offset)
            {
@@ -4106,15 +4366,12 @@ store_constructor (exp, target, align, cleared)
                offset = build (WITH_RECORD_EXPR, sizetype,
                                offset, make_tree (TREE_TYPE (exp), target));
 
-             offset = size_binop (FLOOR_DIV_EXPR, offset,
-                                  size_int (BITS_PER_UNIT));
-
              offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
              if (GET_CODE (to_rtx) != MEM)
                abort ();
 
-              if (GET_MODE (offset_rtx) != ptr_mode)
-                {
+             if (GET_MODE (offset_rtx) != ptr_mode)
+               {
 #ifdef POINTERS_EXTEND_UNSIGNED
                   offset_rtx = convert_memory_address (ptr_mode, offset_rtx);
 #else
@@ -4127,6 +4384,7 @@ store_constructor (exp, target, align, cleared)
                                  gen_rtx_PLUS (ptr_mode, XEXP (to_rtx, 0),
                                                force_reg (ptr_mode,
                                                           offset_rtx)));
+             align = DECL_OFFSET_ALIGN (field);
            }
 
          if (TREE_READONLY (field))
@@ -4142,14 +4400,13 @@ store_constructor (exp, target, align, cleared)
             start of a word, try to widen it to a full word.
             This special case allows us to output C++ member function
             initializations in a form that the optimizers can understand.  */
-         if (constant
-             && GET_CODE (target) == REG
+         if (GET_CODE (target) == REG
              && bitsize < BITS_PER_WORD
              && bitpos % BITS_PER_WORD == 0
              && GET_MODE_CLASS (mode) == MODE_INT
              && TREE_CODE (value) == INTEGER_CST
-             && GET_CODE (exp_size) == CONST_INT
-             && bitpos + BITS_PER_WORD <= INTVAL (exp_size) * BITS_PER_UNIT)
+             && exp_size >= 0
+             && bitpos + BITS_PER_WORD <= exp_size * BITS_PER_UNIT)
            {
              tree type = TREE_TYPE (value);
              if (TYPE_PRECISION (type) < BITS_PER_WORD)
@@ -4166,10 +4423,10 @@ store_constructor (exp, target, align, cleared)
            }
 #endif
          store_constructor_field (to_rtx, bitsize, bitpos, mode,
-                                  TREE_VALUE (elt), type, 
-                                  MIN (align,
-                                       DECL_ALIGN (TREE_PURPOSE (elt))),
-                                  cleared);
+                                  TREE_VALUE (elt), type, align, cleared,
+                                  DECL_NONADDRESSABLE_P (field)
+                                  ? MEM_ALIAS_SET (to_rtx)
+                                  : get_alias_set (TREE_TYPE (field)));
        }
     }
   else if (TREE_CODE (type) == ARRAY_TYPE)
@@ -4178,9 +4435,18 @@ store_constructor (exp, target, align, cleared)
       register int i;
       int need_to_clear;
       tree domain = TYPE_DOMAIN (type);
-      HOST_WIDE_INT minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain));
-      HOST_WIDE_INT maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain));
       tree elttype = TREE_TYPE (type);
+      int const_bounds_p = (host_integerp (TYPE_MIN_VALUE (domain), 0)
+                           && host_integerp (TYPE_MAX_VALUE (domain), 0));
+      HOST_WIDE_INT minelt;
+      HOST_WIDE_INT maxelt;
+
+      /* If we have constant bounds for the range of the type, get them.  */
+      if (const_bounds_p)
+       {
+         minelt = tree_low_cst (TYPE_MIN_VALUE (domain), 0);
+         maxelt = tree_low_cst (TYPE_MAX_VALUE (domain), 0);
+       }
 
       /* If the constructor has fewer elements than the array,
          clear the whole array first.  Similarly if this is
@@ -4190,46 +4456,52 @@ store_constructor (exp, target, align, cleared)
       else
        {
          HOST_WIDE_INT count = 0, zero_count = 0;
-         need_to_clear = 0;
+         need_to_clear = ! const_bounds_p;
+
          /* This loop is a more accurate version of the loop in
             mostly_zeros_p (it handles RANGE_EXPR in an index).
             It is also needed to check for missing elements.  */
          for (elt = CONSTRUCTOR_ELTS (exp);
-              elt != NULL_TREE;
+              elt != NULL_TREE && ! need_to_clear;
               elt = TREE_CHAIN (elt))
            {
              tree index = TREE_PURPOSE (elt);
              HOST_WIDE_INT this_node_count;
+
              if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
                {
                  tree lo_index = TREE_OPERAND (index, 0);
                  tree hi_index = TREE_OPERAND (index, 1);
-                 if (TREE_CODE (lo_index) != INTEGER_CST
-                     || TREE_CODE (hi_index) != INTEGER_CST)
+
+                 if (! host_integerp (lo_index, 1)
+                     || ! host_integerp (hi_index, 1))
                    {
                      need_to_clear = 1;
                      break;
                    }
-                 this_node_count = TREE_INT_CST_LOW (hi_index)
-                   - TREE_INT_CST_LOW (lo_index) + 1;
+
+                 this_node_count = (tree_low_cst (hi_index, 1)
+                                    - tree_low_cst (lo_index, 1) + 1);
                }
              else
                this_node_count = 1;
+
              count += this_node_count;
              if (mostly_zeros_p (TREE_VALUE (elt)))
                zero_count += this_node_count;
            }
+
          /* Clear the entire array first if there are any missing elements,
             or if the incidence of zero elements is >= 75%.  */
-         if (count < maxelt - minelt + 1
-             || 4 * zero_count >= 3 * count)
+         if (! need_to_clear
+             && (count < maxelt - minelt + 1 || 4 * zero_count >= 3 * count))
            need_to_clear = 1;
        }
-      if (need_to_clear)
+
+      if (need_to_clear && size > 0)
        {
          if (! cleared)
-           clear_storage (target, expr_size (exp),
-                          (align + BITS_PER_UNIT - 1) / BITS_PER_UNIT);
+           clear_storage (target, GEN_INT (size), align);
          cleared = 1;
        }
       else
@@ -4244,20 +4516,25 @@ store_constructor (exp, target, align, cleared)
           elt = TREE_CHAIN (elt), i++)
        {
          register enum machine_mode mode;
-         int bitsize;
-         int bitpos;
+         HOST_WIDE_INT bitsize;
+         HOST_WIDE_INT bitpos;
          int unsignedp;
          tree value = TREE_VALUE (elt);
-         int align = TYPE_ALIGN (TREE_TYPE (value));
+         unsigned int align = TYPE_ALIGN (TREE_TYPE (value));
          tree index = TREE_PURPOSE (elt);
          rtx xtarget = target;
 
          if (cleared && is_zeros_p (value))
            continue;
 
-         mode = TYPE_MODE (elttype);
-         bitsize = GET_MODE_BITSIZE (mode);
          unsignedp = TREE_UNSIGNED (elttype);
+         mode = TYPE_MODE (elttype);
+         if (mode == BLKmode)
+           bitsize = (host_integerp (TYPE_SIZE (elttype), 1)
+                      ? tree_low_cst (TYPE_SIZE (elttype), 1)
+                      : -1);
+         else
+           bitsize = GET_MODE_BITSIZE (mode);
 
          if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
            {
@@ -4269,23 +4546,27 @@ store_constructor (exp, target, align, cleared)
              tree position;
 
              /* If the range is constant and "small", unroll the loop.  */
-             if (TREE_CODE (lo_index) == INTEGER_CST
-                 && TREE_CODE (hi_index) == INTEGER_CST
-                 && (lo = TREE_INT_CST_LOW (lo_index),
-                     hi = TREE_INT_CST_LOW (hi_index),
+             if (const_bounds_p
+                 && host_integerp (lo_index, 0)
+                 && host_integerp (hi_index, 0)
+                 && (lo = tree_low_cst (lo_index, 0),
+                     hi = tree_low_cst (hi_index, 0),
                      count = hi - lo + 1,
                      (GET_CODE (target) != MEM
                       || count <= 2
-                      || (TREE_CODE (TYPE_SIZE (elttype)) == INTEGER_CST
-                          && TREE_INT_CST_LOW (TYPE_SIZE (elttype)) * count
-                          <= 40 * 8))))
+                      || (host_integerp (TYPE_SIZE (elttype), 1)
+                          && (tree_low_cst (TYPE_SIZE (elttype), 1) * count
+                              <= 40 * 8)))))
                {
                  lo -= minelt;  hi -= minelt;
                  for (; lo <= hi; lo++)
                    {
-                     bitpos = lo * TREE_INT_CST_LOW (TYPE_SIZE (elttype));
-                     store_constructor_field (target, bitsize, bitpos, mode,
-                                              value, type, align, cleared);
+                     bitpos = lo * tree_low_cst (TYPE_SIZE (elttype), 0);
+                     store_constructor_field
+                       (target, bitsize, bitpos, mode, value, type, align,
+                        cleared,
+                        TYPE_NONALIASED_COMPONENT (type)
+                        ? MEM_ALIAS_SET (target) : get_alias_set (elttype));
                    }
                }
              else
@@ -4314,17 +4595,20 @@ store_constructor (exp, target, align, cleared)
                  loop = expand_start_loop (0);
 
                  /* Assign value to element index.  */
-                 position = size_binop (EXACT_DIV_EXPR, TYPE_SIZE (elttype),
-                                        size_int (BITS_PER_UNIT));
-                 position = size_binop (MULT_EXPR,
-                                        size_binop (MINUS_EXPR, index,
-                                                    TYPE_MIN_VALUE (domain)),
-                                        position);
+                 position
+                   = convert (ssizetype,
+                              fold (build (MINUS_EXPR, TREE_TYPE (index),
+                                           index, TYPE_MIN_VALUE (domain))));
+                 position = size_binop (MULT_EXPR, position,
+                                        convert (ssizetype,
+                                                 TYPE_SIZE_UNIT (elttype)));
+
                  pos_rtx = expand_expr (position, 0, VOIDmode, 0);
                  addr = gen_rtx_PLUS (Pmode, XEXP (target, 0), pos_rtx);
                  xtarget = change_address (target, mode, addr);
                  if (TREE_CODE (value) == CONSTRUCTOR)
-                   store_constructor (value, xtarget, align, cleared);
+                   store_constructor (value, xtarget, align, cleared,
+                                      bitsize / BITS_PER_UNIT);
                  else
                    store_expr (value, xtarget, 0);
 
@@ -4337,28 +4621,25 @@ store_constructor (exp, target, align, cleared)
                                           index, integer_one_node), 0, 0);
                  expand_end_loop ();
                  emit_label (loop_end);
-
-                 /* Needed by stupid register allocation. to extend the
-                    lifetime of pseudo-regs used by target past the end
-                    of the loop.  */
-                 emit_insn (gen_rtx_USE (GET_MODE (target), target));
                }
            }
-         else if ((index != 0 && TREE_CODE (index) != INTEGER_CST)
-             || TREE_CODE (TYPE_SIZE (elttype)) != INTEGER_CST)
+         else if ((index != 0 && ! host_integerp (index, 0))
+                  || ! host_integerp (TYPE_SIZE (elttype), 1))
            {
              rtx pos_rtx, addr;
              tree position;
 
              if (index == 0)
-               index = size_int (i);
+               index = ssize_int (1);
 
              if (minelt)
-               index = size_binop (MINUS_EXPR, index,
-                                   TYPE_MIN_VALUE (domain));
-             position = size_binop (EXACT_DIV_EXPR, TYPE_SIZE (elttype),
-                                    size_int (BITS_PER_UNIT));
-             position = size_binop (MULT_EXPR, index, position);
+               index = convert (ssizetype,
+                                fold (build (MINUS_EXPR, index,
+                                             TYPE_MIN_VALUE (domain))));
+
+             position = size_binop (MULT_EXPR, index,
+                                    convert (ssizetype,
+                                             TYPE_SIZE_UNIT (elttype)));
              pos_rtx = expand_expr (position, 0, VOIDmode, 0);
              addr = gen_rtx_PLUS (Pmode, XEXP (target, 0), pos_rtx);
              xtarget = change_address (target, mode, addr);
@@ -4367,20 +4648,26 @@ store_constructor (exp, target, align, cleared)
          else
            {
              if (index != 0)
-               bitpos = ((TREE_INT_CST_LOW (index) - minelt)
-                         * TREE_INT_CST_LOW (TYPE_SIZE (elttype)));
+               bitpos = ((tree_low_cst (index, 0) - minelt)
+                         * tree_low_cst (TYPE_SIZE (elttype), 1));
              else
-               bitpos = (i * TREE_INT_CST_LOW (TYPE_SIZE (elttype)));
+               bitpos = (i * tree_low_cst (TYPE_SIZE (elttype), 1));
+
              store_constructor_field (target, bitsize, bitpos, mode, value,
-                                      type, align, cleared);
+                                      type, align, cleared,
+                                      TYPE_NONALIASED_COMPONENT (type)
+                                      ? MEM_ALIAS_SET (target) :
+                                      get_alias_set (elttype));
+
            }
        }
     }
-  /* set constructor assignments */
+
+  /* Set constructor assignments.  */
   else if (TREE_CODE (type) == SET_TYPE)
     {
       tree elt = CONSTRUCTOR_ELTS (exp);
-      int nbytes = int_size_in_bytes (type), nbits;
+      unsigned HOST_WIDE_INT nbytes = int_size_in_bytes (type), nbits;
       tree domain = TYPE_DOMAIN (type);
       tree domain_min, domain_max, bitlength;
 
@@ -4393,39 +4680,37 @@ store_constructor (exp, target, align, cleared)
         Also, if a large set has just a single range, it may also be
         better to first clear all the first clear the set (using
         bzero/memset), and set the bits we want.  */
-       
+
       /* Check for all zeros.  */
-      if (elt == NULL_TREE)
+      if (elt == NULL_TREE && size > 0)
        {
          if (!cleared)
-           clear_storage (target, expr_size (exp),
-                          TYPE_ALIGN (type) / BITS_PER_UNIT);
+           clear_storage (target, GEN_INT (size), TYPE_ALIGN (type));
          return;
        }
 
       domain_min = convert (sizetype, TYPE_MIN_VALUE (domain));
       domain_max = convert (sizetype, TYPE_MAX_VALUE (domain));
       bitlength = size_binop (PLUS_EXPR,
-                             size_binop (MINUS_EXPR, domain_max, domain_min),
-                             size_one_node);
+                             size_diffop (domain_max, domain_min),
+                             ssize_int (1));
 
-      if (nbytes < 0 || TREE_CODE (bitlength) != INTEGER_CST)
-       abort ();
-      nbits = TREE_INT_CST_LOW (bitlength);
+      nbits = tree_low_cst (bitlength, 1);
 
       /* For "small" sets, or "medium-sized" (up to 32 bytes) sets that
         are "complicated" (more than one range), initialize (the
-        constant parts) by copying from a constant.  */         
+        constant parts) by copying from a constant.  */
       if (GET_MODE (target) != BLKmode || nbits <= 2 * BITS_PER_WORD
          || (nbytes <= 32 && TREE_CHAIN (elt) != NULL_TREE))
        {
-         int set_word_size = TYPE_ALIGN (TREE_TYPE (exp));
+         unsigned int set_word_size = TYPE_ALIGN (TREE_TYPE (exp));
          enum machine_mode mode = mode_for_size (set_word_size, MODE_INT, 1);
          char *bit_buffer = (char *) alloca (nbits);
          HOST_WIDE_INT word = 0;
-         int bit_pos = 0;
-         int ibit = 0;
-         int offset = 0;  /* In bytes from beginning of set.  */
+         unsigned int bit_pos = 0;
+         unsigned int ibit = 0;
+         unsigned int offset = 0;  /* In bytes from beginning of set.  */
+
          elt = get_set_constructor_bits (exp, bit_buffer, nbits);
          for (;;)
            {
@@ -4436,6 +4721,7 @@ store_constructor (exp, target, align, cleared)
                  else
                    word |= 1 << bit_pos;
                }
+
              bit_pos++;  ibit++;
              if (bit_pos >= set_word_size || ibit == nbits)
                {
@@ -4443,6 +4729,7 @@ store_constructor (exp, target, align, cleared)
                    {
                      rtx datum = GEN_INT (word);
                      rtx to_rtx;
+
                      /* The assumption here is that it is safe to use
                         XEXP if the set is multi-word, but not if
                         it's single-word.  */
@@ -4451,12 +4738,13 @@ store_constructor (exp, target, align, cleared)
                          to_rtx = plus_constant (XEXP (target, 0), offset);
                          to_rtx = change_address (target, mode, to_rtx);
                        }
-                     else if (offset == 0) 
+                     else if (offset == 0)
                        to_rtx = target;
                      else
                        abort ();
                      emit_move_insn (to_rtx, datum);
                    }
+
                  if (ibit == nbits)
                    break;
                  word = 0;
@@ -4466,40 +4754,38 @@ store_constructor (exp, target, align, cleared)
            }
        }
       else if (!cleared)
-       {
-         /* Don't bother clearing storage if the set is all ones.  */
-         if (TREE_CHAIN (elt) != NULL_TREE
-             || (TREE_PURPOSE (elt) == NULL_TREE
-                 ? nbits != 1
-                 : (TREE_CODE (TREE_VALUE (elt)) != INTEGER_CST
-                    || TREE_CODE (TREE_PURPOSE (elt)) != INTEGER_CST
-                    || (TREE_INT_CST_LOW (TREE_VALUE (elt))
-                        - TREE_INT_CST_LOW (TREE_PURPOSE (elt)) + 1
-                        != nbits))))
-           clear_storage (target, expr_size (exp),
-                          TYPE_ALIGN (type) / BITS_PER_UNIT);
-       }
-         
+       /* Don't bother clearing storage if the set is all ones.  */
+       if (TREE_CHAIN (elt) != NULL_TREE
+           || (TREE_PURPOSE (elt) == NULL_TREE
+               ? nbits != 1
+               : ( ! host_integerp (TREE_VALUE (elt), 0)
+                  || ! host_integerp (TREE_PURPOSE (elt), 0)
+                  || (tree_low_cst (TREE_VALUE (elt), 0)
+                      - tree_low_cst (TREE_PURPOSE (elt), 0) + 1
+                      != (HOST_WIDE_INT) nbits))))
+         clear_storage (target, expr_size (exp), TYPE_ALIGN (type));
+
       for (; elt != NULL_TREE; elt = TREE_CHAIN (elt))
        {
-         /* start of range of element or NULL */
+         /* Start of range of element or NULL.  */
          tree startbit = TREE_PURPOSE (elt);
-         /* end of range of element, or element value */
+         /* End of range of element, or element value.  */
          tree endbit   = TREE_VALUE (elt);
 #ifdef TARGET_MEM_FUNCTIONS
          HOST_WIDE_INT startb, endb;
 #endif
-         rtx  bitlength_rtx, startbit_rtx, endbit_rtx, targetx;
+         rtx bitlength_rtx, startbit_rtx, endbit_rtx, targetx;
 
          bitlength_rtx = expand_expr (bitlength,
-                           NULL_RTX, MEM, EXPAND_CONST_ADDRESS);
+                                      NULL_RTX, MEM, EXPAND_CONST_ADDRESS);
 
-         /* handle non-range tuple element like [ expr ]  */
+         /* Handle non-range tuple element like [ expr ].  */
          if (startbit == NULL_TREE)
            {
              startbit = save_expr (endbit);
              endbit = startbit;
            }
+
          startbit = convert (sizetype, startbit);
          endbit = convert (sizetype, endbit);
          if (! integer_zerop (domain_min))
@@ -4507,9 +4793,9 @@ store_constructor (exp, target, align, cleared)
              startbit = size_binop (MINUS_EXPR, startbit, domain_min);
              endbit = size_binop (MINUS_EXPR, endbit, domain_min);
            }
-         startbit_rtx = expand_expr (startbit, NULL_RTX, MEM, 
+         startbit_rtx = expand_expr (startbit, NULL_RTX, MEM,
                                      EXPAND_CONST_ADDRESS);
-         endbit_rtx = expand_expr (endbit, NULL_RTX, MEM, 
+         endbit_rtx = expand_expr (endbit, NULL_RTX, MEM,
                                    EXPAND_CONST_ADDRESS);
 
          if (REG_P (target))
@@ -4519,6 +4805,7 @@ store_constructor (exp, target, align, cleared)
                                           0);
              emit_move_insn (targetx, target);
            }
+
          else if (GET_CODE (target) == MEM)
            targetx = target;
          else
@@ -4533,7 +4820,7 @@ store_constructor (exp, target, align, cleared)
              && (startb = TREE_INT_CST_LOW (startbit)) % BITS_PER_UNIT == 0
              && (endb = TREE_INT_CST_LOW (endbit) + 1) % BITS_PER_UNIT == 0)
            {
-             emit_library_call (memset_libfunc, 0,
+             emit_library_call (memset_libfunc, LCT_NORMAL,
                                 VOIDmode, 3,
                                 plus_constant (XEXP (targetx, 0),
                                                startb / BITS_PER_UNIT),
@@ -4544,13 +4831,12 @@ store_constructor (exp, target, align, cleared)
            }
          else
 #endif
-           {
-             emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__setbits"),
-                                0, VOIDmode, 4, XEXP (targetx, 0), Pmode,
-                                bitlength_rtx, TYPE_MODE (sizetype),
-                                startbit_rtx, TYPE_MODE (sizetype),
-                                endbit_rtx, TYPE_MODE (sizetype));
-           }
+           emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__setbits"),
+                              LCT_NORMAL, VOIDmode, 4, XEXP (targetx, 0),
+                              Pmode, bitlength_rtx, TYPE_MODE (sizetype),
+                              startbit_rtx, TYPE_MODE (sizetype),
+                              endbit_rtx, TYPE_MODE (sizetype));
+
          if (REG_P (target))
            emit_move_insn (target, targetx);
        }
@@ -4572,8 +4858,8 @@ store_constructor (exp, target, align, cleared)
    has mode VALUE_MODE if that is convenient to do.
    In this case, UNSIGNEDP must be nonzero if the value is an unsigned type.
 
-   ALIGN is the alignment that TARGET is known to have, measured in bytes.
-   TOTAL_SIZE is the size in bytes of the structure, or -1 if varying.  
+   ALIGN is the alignment that TARGET is known to have.
+   TOTAL_SIZE is the size in bytes of the structure, or -1 if varying.
 
    ALIAS_SET is the alias set for the destination.  This value will
    (in general) be different from that for TARGET, since TARGET is a
@@ -4583,13 +4869,14 @@ static rtx
 store_field (target, bitsize, bitpos, mode, exp, value_mode,
             unsignedp, align, total_size, alias_set)
      rtx target;
-     int bitsize, bitpos;
+     HOST_WIDE_INT bitsize;
+     HOST_WIDE_INT bitpos;
      enum machine_mode mode;
      tree exp;
      enum machine_mode value_mode;
      int unsignedp;
-     int align;
-     int total_size;
+     unsigned int align;
+     HOST_WIDE_INT total_size;
      int alias_set;
 {
   HOST_WIDE_INT width_mask = 0;
@@ -4635,6 +4922,15 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
       return blk_object;
     }
 
+  if (GET_CODE (target) == CONCAT)
+    {
+      /* We're storing into a struct containing a single __complex.  */
+
+      if (bitpos != 0)
+       abort ();
+      return store_expr (exp, target, 0);
+    }
+
   /* If the structure is in a register or if the component
      is a bit field, we cannot use addressing to access it.
      Use bit-field techniques or SUBREG to store in it.  */
@@ -4647,9 +4943,18 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
       || GET_CODE (target) == SUBREG
       /* If the field isn't aligned enough to store as an ordinary memref,
         store it as a bit field.  */
-      || (SLOW_UNALIGNED_ACCESS
-         && align * BITS_PER_UNIT < GET_MODE_ALIGNMENT (mode))
-      || (SLOW_UNALIGNED_ACCESS && bitpos % GET_MODE_ALIGNMENT (mode) != 0))
+      || (mode != BLKmode && SLOW_UNALIGNED_ACCESS (mode, align)
+         && (align < GET_MODE_ALIGNMENT (mode)
+             || bitpos % GET_MODE_ALIGNMENT (mode)))
+      || (mode == BLKmode && SLOW_UNALIGNED_ACCESS (mode, align)
+         && (TYPE_ALIGN (TREE_TYPE (exp)) > align
+             || bitpos % TYPE_ALIGN (TREE_TYPE (exp)) != 0))
+      /* If the RHS and field are a constant size and the size of the
+        RHS isn't the same size as the bitfield, we must use bitfield
+        operations.  */
+      || (bitsize >= 0
+         && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
+         && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0))
     {
       rtx temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
 
@@ -4676,6 +4981,8 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
         boundary.  If so, we simply do a block copy.  */
       if (GET_MODE (target) == BLKmode && GET_MODE (temp) == BLKmode)
        {
+         unsigned int exp_align = expr_align (exp);
+
          if (GET_CODE (target) != MEM || GET_CODE (temp) != MEM
              || bitpos % BITS_PER_UNIT != 0)
            abort ();
@@ -4684,10 +4991,18 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
                                   plus_constant (XEXP (target, 0),
                                                bitpos / BITS_PER_UNIT));
 
+         /* Make sure that ALIGN is no stricter than the alignment of EXP.  */
+         align = MIN (exp_align, align);
+
+         /* Find an alignment that is consistent with the bit position.  */
+         while ((bitpos % align) != 0)
+           align >>= 1;
+
          emit_block_move (target, temp,
-                          GEN_INT ((bitsize + BITS_PER_UNIT - 1)
-                                   / BITS_PER_UNIT),
-                          1);
+                          bitsize == -1 ? expr_size (exp)
+                          : GEN_INT ((bitsize + BITS_PER_UNIT - 1)
+                                     / BITS_PER_UNIT),
+                          align);
 
          return value_mode == VOIDmode ? const0_rtx : target;
        }
@@ -4759,7 +5074,7 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
    giving the variable offset (in units) in *POFFSET.
    This offset is in addition to the bit position.
    If the position is not variable, we store 0 in *POFFSET.
-   We set *PALIGNMENT to the alignment in bytes of the address that will be
+   We set *PALIGNMENT to the alignment of the address that will be
    computed.  This is the alignment of the thing we return if *POFFSET
    is zero, but can be more less strictly aligned if *POFFSET is nonzero.
 
@@ -4778,25 +5093,29 @@ tree
 get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
                     punsignedp, pvolatilep, palignment)
      tree exp;
-     int *pbitsize;
-     int *pbitpos;
+     HOST_WIDE_INT *pbitsize;
+     HOST_WIDE_INT *pbitpos;
      tree *poffset;
      enum machine_mode *pmode;
      int *punsignedp;
      int *pvolatilep;
-     int *palignment;
+     unsigned int *palignment;
 {
-  tree orig_exp = exp;
   tree size_tree = 0;
   enum machine_mode mode = VOIDmode;
-  tree offset = integer_zero_node;
+  tree offset = size_zero_node;
+  tree bit_offset = bitsize_zero_node;
   unsigned int alignment = BIGGEST_ALIGNMENT;
+  tree tem;
 
+  /* First get the mode, signedness, and size.  We do this from just the
+     outermost expression.  */
   if (TREE_CODE (exp) == COMPONENT_REF)
     {
       size_tree = DECL_SIZE (TREE_OPERAND (exp, 1));
       if (! DECL_BIT_FIELD (TREE_OPERAND (exp, 1)))
        mode = DECL_MODE (TREE_OPERAND (exp, 1));
+
       *punsignedp = TREE_UNSIGNED (TREE_OPERAND (exp, 1));
     }
   else if (TREE_CODE (exp) == BIT_FIELD_REF)
@@ -4807,125 +5126,85 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
   else
     {
       mode = TYPE_MODE (TREE_TYPE (exp));
+      *punsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
+
       if (mode == BLKmode)
        size_tree = TYPE_SIZE (TREE_TYPE (exp));
-
-      *pbitsize = GET_MODE_BITSIZE (mode);
-      *punsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
+      else
+       *pbitsize = GET_MODE_BITSIZE (mode);
     }
-      
-  if (size_tree)
+
+  if (size_tree != 0)
     {
-      if (TREE_CODE (size_tree) != INTEGER_CST)
+      if (! host_integerp (size_tree, 1))
        mode = BLKmode, *pbitsize = -1;
       else
-       *pbitsize = TREE_INT_CST_LOW (size_tree);
+       *pbitsize = tree_low_cst (size_tree, 1);
     }
 
   /* Compute cumulative bit-offset for nested component-refs and array-refs,
      and find the ultimate containing object.  */
-
-  *pbitpos = 0;
-
   while (1)
     {
-      if (TREE_CODE (exp) == COMPONENT_REF || TREE_CODE (exp) == BIT_FIELD_REF)
+      if (TREE_CODE (exp) == BIT_FIELD_REF)
+       bit_offset = size_binop (PLUS_EXPR, bit_offset, TREE_OPERAND (exp, 2));
+      else if (TREE_CODE (exp) == COMPONENT_REF)
        {
-         tree pos = (TREE_CODE (exp) == COMPONENT_REF
-                     ? DECL_FIELD_BITPOS (TREE_OPERAND (exp, 1))
-                     : TREE_OPERAND (exp, 2));
-         tree constant = integer_zero_node, var = pos;
+         tree field = TREE_OPERAND (exp, 1);
+         tree this_offset = DECL_FIELD_OFFSET (field);
 
          /* If this field hasn't been filled in yet, don't go
             past it.  This should only happen when folding expressions
             made during type construction.  */
-         if (pos == 0)
+         if (this_offset == 0)
            break;
+         else if (! TREE_CONSTANT (this_offset)
+                  && contains_placeholder_p (this_offset))
+           this_offset = build (WITH_RECORD_EXPR, sizetype, this_offset, exp);
 
-         /* Assume here that the offset is a multiple of a unit.
-            If not, there should be an explicitly added constant.  */
-         if (TREE_CODE (pos) == PLUS_EXPR
-             && TREE_CODE (TREE_OPERAND (pos, 1)) == INTEGER_CST)
-           constant = TREE_OPERAND (pos, 1), var = TREE_OPERAND (pos, 0);
-         else if (TREE_CODE (pos) == INTEGER_CST)
-           constant = pos, var = integer_zero_node;
+         offset = size_binop (PLUS_EXPR, offset, this_offset);
+         bit_offset = size_binop (PLUS_EXPR, bit_offset,
+                                  DECL_FIELD_BIT_OFFSET (field));
 
-         *pbitpos += TREE_INT_CST_LOW (constant);
-         offset = size_binop (PLUS_EXPR, offset,
-                              size_binop (EXACT_DIV_EXPR, var,
-                                          size_int (BITS_PER_UNIT)));
+         if (! host_integerp (offset, 0))
+           alignment = MIN (alignment, DECL_OFFSET_ALIGN (field));
        }
 
       else if (TREE_CODE (exp) == ARRAY_REF)
        {
-         /* This code is based on the code in case ARRAY_REF in expand_expr
-            below.  We assume here that the size of an array element is
-            always an integral multiple of BITS_PER_UNIT.  */
-
          tree index = TREE_OPERAND (exp, 1);
          tree domain = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0)));
-         tree low_bound
-           = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
-         tree index_type = TREE_TYPE (index);
-         tree xindex;
+         tree low_bound = (domain ? TYPE_MIN_VALUE (domain) : 0);
+         tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (exp));
+
+         /* We assume all arrays have sizes that are a multiple of a byte.
+            First subtract the lower bound, if any, in the type of the
+            index, then convert to sizetype and multiply by the size of the
+            array element.  */
+         if (low_bound != 0 && ! integer_zerop (low_bound))
+           index = fold (build (MINUS_EXPR, TREE_TYPE (index),
+                                index, low_bound));
+
+         /* If the index has a self-referential type, pass it to a
+            WITH_RECORD_EXPR; if the component size is, pass our
+            component to one.  */
+         if (! TREE_CONSTANT (index)
+             && contains_placeholder_p (index))
+           index = build (WITH_RECORD_EXPR, TREE_TYPE (index), index, exp);
+         if (! TREE_CONSTANT (unit_size)
+             && contains_placeholder_p (unit_size))
+           unit_size = build (WITH_RECORD_EXPR, sizetype, unit_size,
+                              TREE_OPERAND (exp, 0));
 
-         if (TYPE_PRECISION (index_type) != TYPE_PRECISION (sizetype))
-           {
-             index = convert (type_for_size (TYPE_PRECISION (sizetype), 0),
-                              index);
-             index_type = TREE_TYPE (index);
-           }
-
-         /* Optimize the special-case of a zero lower bound.
-            
-            We convert the low_bound to sizetype to avoid some problems
-            with constant folding.  (E.g. suppose the lower bound is 1,
-            and its mode is QI.  Without the conversion,  (ARRAY
-            +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
-            +INDEX), which becomes (ARRAY+255+INDEX).  Oops!)
-            
-            But sizetype isn't quite right either (especially if
-            the lowbound is negative).  FIXME */
-
-         if (! integer_zerop (low_bound))
-           index = fold (build (MINUS_EXPR, index_type, index,
-                                convert (sizetype, low_bound)));
-
-         if (TREE_CODE (index) == INTEGER_CST)
-           {
-             index = convert (sbitsizetype, index);
-             index_type = TREE_TYPE (index);
-           }
-
-         xindex = fold (build (MULT_EXPR, sbitsizetype, index,
-                               convert (sbitsizetype,
-                                        TYPE_SIZE (TREE_TYPE (exp)))));
-
-         if (TREE_CODE (xindex) == INTEGER_CST
-             && TREE_INT_CST_HIGH (xindex) == 0)
-           *pbitpos += TREE_INT_CST_LOW (xindex);
-         else
-           {
-             /* Either the bit offset calculated above is not constant, or
-                it overflowed.  In either case, redo the multiplication
-                against the size in units.  This is especially important
-                in the non-constant case to avoid a division at runtime.  */
-             xindex = fold (build (MULT_EXPR, ssizetype, index,
-                                    convert (ssizetype,
-                                         TYPE_SIZE_UNIT (TREE_TYPE (exp)))));
-
-             if (contains_placeholder_p (xindex))
-               xindex = build (WITH_RECORD_EXPR, sizetype, xindex, exp);
-
-             offset = size_binop (PLUS_EXPR, offset, xindex);
-           }
+         offset = size_binop (PLUS_EXPR, offset,
+                              size_binop (MULT_EXPR,
+                                          convert (sizetype, index),
+                                          unit_size));
        }
+
       else if (TREE_CODE (exp) != NON_LVALUE_EXPR
               && ! ((TREE_CODE (exp) == NOP_EXPR
                      || TREE_CODE (exp) == CONVERT_EXPR)
-                    && ! (TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE
-                          && (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0)))
-                              != UNION_TYPE))
                     && (TYPE_MODE (TREE_TYPE (exp))
                         == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))))
        break;
@@ -4936,30 +5215,35 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
 
       /* If the offset is non-constant already, then we can't assume any
         alignment more than the alignment here.  */
-      if (! integer_zerop (offset))
+      if (! TREE_CONSTANT (offset))
        alignment = MIN (alignment, TYPE_ALIGN (TREE_TYPE (exp)));
 
       exp = TREE_OPERAND (exp, 0);
     }
 
-  if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'd')
+  if (DECL_P (exp))
     alignment = MIN (alignment, DECL_ALIGN (exp));
   else if (TREE_TYPE (exp) != 0)
     alignment = MIN (alignment, TYPE_ALIGN (TREE_TYPE (exp)));
 
-  if (integer_zerop (offset))
-    offset = 0;
-
-  if (offset != 0 && contains_placeholder_p (offset))
-    offset = build (WITH_RECORD_EXPR, sizetype, offset, orig_exp);
+  /* If OFFSET is constant, see if we can return the whole thing as a
+     constant bit position.  Otherwise, split it up.  */
+  if (host_integerp (offset, 0)
+      && 0 != (tem = size_binop (MULT_EXPR, convert (bitsizetype, offset),
+                                bitsize_unit_node))
+      && 0 != (tem = size_binop (PLUS_EXPR, tem, bit_offset))
+      && host_integerp (tem, 0))
+    *pbitpos = tree_low_cst (tem, 0), *poffset = 0;
+  else
+    *pbitpos = tree_low_cst (bit_offset, 0), *poffset = offset;
 
   *pmode = mode;
-  *poffset = offset;
-  *palignment = alignment / BITS_PER_UNIT;
+  *palignment = alignment;
   return exp;
 }
 
 /* Subroutine of expand_exp: compute memory_usage from modifier.  */
+
 static enum memory_use_mode
 get_memory_usage_from_modifier (modifier)
      enum expand_modifier modifier;
@@ -5006,7 +5290,7 @@ force_operand (value, target)
   rtx tmp;
   register rtx op2;
   /* Use subtarget as the target for operand 0 of a binary operation.  */
-  register rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0);
+  register rtx subtarget = get_subtarget (target);
 
   /* Check for a PIC address load.  */
   if (flag_pic
@@ -5069,7 +5353,7 @@ force_operand (value, target)
                               force_operand (XEXP (XEXP (value, 0), 1), 0),
                               target, 0, OPTAB_LIB_WIDEN);
        }
-                                  
+
       tmp = force_operand (XEXP (value, 0), subtarget);
       return expand_binop (GET_MODE (value), binoptab, tmp,
                           force_operand (op2, NULL_RTX),
@@ -5146,7 +5430,7 @@ init_noncopied_parts (lhs, list)
    It is always safe for this routine to return zero since it merely
    searches for optimization opportunities.  */
 
-static int
+int
 safe_from_p (x, exp, top_p)
      rtx x;
      tree exp;
@@ -5166,7 +5450,7 @@ safe_from_p (x, exp, top_p)
         So we assume here that something at a higher level has prevented a
         clash.  This is somewhat bogus, but the best we can do.  Only
         do this when X is BLKmode and when we are at the top level.  */
-      || (top_p && TREE_TYPE (exp) != 0 && TYPE_SIZE (TREE_TYPE (exp)) != 0
+      || (top_p && TREE_TYPE (exp) != 0 && COMPLETE_TYPE_P (TREE_TYPE (exp))
          && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST
          && (TREE_CODE (TREE_TYPE (exp)) != ARRAY_TYPE
              || TYPE_ARRAY_MAX_SIZE (TREE_TYPE (exp)) == NULL_TREE
@@ -5180,7 +5464,7 @@ safe_from_p (x, exp, top_p)
       int rtn;
 
       save_expr_count = 0;
-      save_expr_size = sizeof (save_expr_trees) / sizeof (save_expr_trees[0]);
+      save_expr_size = ARRAY_SIZE (save_expr_trees);
       save_expr_rewritten = &save_expr_trees[0];
 
       rtn = safe_from_p (x, exp, 1);
@@ -5309,12 +5593,12 @@ safe_from_p (x, exp, top_p)
             where it is so we can turn it back in the top-level safe_from_p()
             when we're done.  */
 
-         /* For now, don't bother re-sizing the array. */
+         /* For now, don't bother re-sizing the array.  */
          if (save_expr_count >= save_expr_size)
            return 0;
          save_expr_rewritten[save_expr_count++] = exp;
 
-         nops = tree_code_length[(int) SAVE_EXPR];
+         nops = TREE_CODE_LENGTH (SAVE_EXPR);
          for (i = 0; i < nops; i++)
            {
              tree operand = TREE_OPERAND (exp, i);
@@ -5336,7 +5620,7 @@ safe_from_p (x, exp, top_p)
        case METHOD_CALL_EXPR:
          /* This takes a rtx argument, but shouldn't appear here.  */
          abort ();
-         
+
        default:
          break;
        }
@@ -5345,11 +5629,18 @@ safe_from_p (x, exp, top_p)
       if (exp_rtl)
        break;
 
-      nops = tree_code_length[(int) TREE_CODE (exp)];
+      nops = first_rtl_op (TREE_CODE (exp));
       for (i = 0; i < nops; i++)
        if (TREE_OPERAND (exp, i) != 0
            && ! safe_from_p (x, TREE_OPERAND (exp, i), 0))
          return 0;
+
+      /* If this is a language-specific tree code, it may require
+        special handling.  */
+      if (TREE_CODE (exp) >= LAST_AND_UNUSED_TREE_CODE
+         && lang_safe_from_p
+         && !(*lang_safe_from_p) (x, exp))
+       return 0;
     }
 
   /* If we have an rtl, find any enclosed object.  Then see if we conflict
@@ -5412,7 +5703,7 @@ var_rtx (exp)
 #ifdef MAX_INTEGER_COMPUTATION_MODE
 void
 check_max_integer_computation_mode (exp)
-    tree exp;
+     tree exp;
 {
   enum tree_code code;
   enum machine_mode mode;
@@ -5446,7 +5737,7 @@ check_max_integer_computation_mode (exp)
          && mode > MAX_INTEGER_COMPUTATION_MODE)
        fatal ("unsupported wide integer operation");
     }
-       
+
   /* Check operands of a binary/comparison op.  */
   if (TREE_CODE_CLASS (code) == '2' || TREE_CODE_CLASS (code) == '<')
     {
@@ -5462,7 +5753,26 @@ check_max_integer_computation_mode (exp)
     }
 }
 #endif
+\f
+/* Utility function used by expand_expr to see if TYPE, a RECORD_TYPE,
+   has any readonly fields.  If any of the fields have types that
+   contain readonly fields, return true as well.  */
 
+static int
+readonly_fields_p (type)
+     tree type;
+{
+  tree field;
+
+  for (field = TYPE_FIELDS (type); field != 0; field = TREE_CHAIN (field))
+    if (TREE_CODE (field) == FIELD_DECL
+       && (TREE_READONLY (field)
+           || (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
+               && readonly_fields_p (TREE_TYPE (field)))))
+      return 1;
+
+  return 0;
+}
 \f
 /* expand_expr: generate code for computing expression EXP.
    An rtx for the computed value is returned.  The value is never null.
@@ -5506,9 +5816,6 @@ expand_expr (exp, target, tmode, modifier)
      enum machine_mode tmode;
      enum expand_modifier modifier;
 {
-  /* Chain of pending expressions for PLACEHOLDER_EXPR to replace.
-     This is static so it will be accessible to our recursive callees.  */
-  static tree placeholder_list = 0;
   register rtx op0, op1, temp;
   tree type = TREE_TYPE (exp);
   int unsignedp = TREE_UNSIGNED (type);
@@ -5521,8 +5828,8 @@ expand_expr (exp, target, tmode, modifier)
   /* Used by check-memory-usage to make modifier read only.  */
   enum expand_modifier ro_modifier;
 
-  /* Handle ERROR_MARK before anybody tries to access its type. */
-  if (TREE_CODE (exp) == ERROR_MARK)
+  /* Handle ERROR_MARK before anybody tries to access its type.  */
+  if (TREE_CODE (exp) == ERROR_MARK || TREE_CODE (type) == ERROR_MARK)
     {
       op0 = CONST0_RTX (tmode);
       if (op0 != 0)
@@ -5532,7 +5839,7 @@ expand_expr (exp, target, tmode, modifier)
 
   mode = TYPE_MODE (type);
   /* Use subtarget as the target for operand 0 of a binary operation.  */
-  subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0);
+  subtarget = get_subtarget (target);
   original_target = target;
   ignore = (target == const0_rtx
            || ((code == NON_LVALUE_EXPR || code == NOP_EXPR
@@ -5547,15 +5854,6 @@ expand_expr (exp, target, tmode, modifier)
   else
     ro_modifier = EXPAND_NORMAL;
 
-  /* Don't use hard regs as subtargets, because the combiner
-     can only handle pseudo regs.  */
-  if (subtarget && REGNO (subtarget) < FIRST_PSEUDO_REGISTER)
-    subtarget = 0;
-  /* Avoid subtargets inside loops,
-     since they hide some invariant expressions.  */
-  if (preserve_subexpressions_p ())
-    subtarget = 0;
-
   /* If we are going to ignore this result, we need only do something
      if there is a side-effect somewhere in the expression.  If there
      is, short-circuit the most common cases here.  Note that we must
@@ -5567,10 +5865,12 @@ expand_expr (exp, target, tmode, modifier)
       if (! TREE_SIDE_EFFECTS (exp))
        return const0_rtx;
 
-      /* Ensure we reference a volatile object even if value is ignored.  */
+      /* Ensure we reference a volatile object even if value is ignored, but
+        don't do this if all we are doing is taking its address.  */
       if (TREE_THIS_VOLATILE (exp)
          && TREE_CODE (exp) != FUNCTION_DECL
-         && mode != VOIDmode && mode != BLKmode)
+         && mode != VOIDmode && mode != BLKmode
+         && modifier != EXPAND_CONST_ADDRESS)
        {
          temp = expand_expr (exp, NULL_RTX, VOIDmode, ro_modifier);
          if (GET_CODE (temp) == MEM)
@@ -5578,11 +5878,12 @@ expand_expr (exp, target, tmode, modifier)
          return const0_rtx;
        }
 
-      if (TREE_CODE_CLASS (code) == '1')
+      if (TREE_CODE_CLASS (code) == '1' || code == COMPONENT_REF
+         || code == INDIRECT_REF || code == BUFFER_REF)
        return expand_expr (TREE_OPERAND (exp, 0), const0_rtx,
                            VOIDmode, ro_modifier);
-      else if (TREE_CODE_CLASS (code) == '2'
-              || TREE_CODE_CLASS (code) == '<')
+      else if (TREE_CODE_CLASS (code) == '2' || TREE_CODE_CLASS (code) == '<'
+              || code == ARRAY_REF)
        {
          expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, ro_modifier);
          expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, ro_modifier);
@@ -5594,7 +5895,14 @@ expand_expr (exp, target, tmode, modifier)
           the first.  */
        return expand_expr (TREE_OPERAND (exp, 0), const0_rtx,
                            VOIDmode, ro_modifier);
-
+      else if (code == BIT_FIELD_REF)
+       {
+         expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, ro_modifier);
+         expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, ro_modifier);
+         expand_expr (TREE_OPERAND (exp, 2), const0_rtx, VOIDmode, ro_modifier);
+         return const0_rtx;
+       }
+      ;
       target = 0;
     }
 
@@ -5696,7 +6004,7 @@ expand_expr (exp, target, tmode, modifier)
     case VAR_DECL:
       /* If a static var's type was incomplete when the decl was written,
         but the type is complete now, lay out the decl now.  */
-      if (DECL_SIZE (exp) == 0 && TYPE_SIZE (TREE_TYPE (exp)) != 0
+      if (DECL_SIZE (exp) == 0 && COMPLETE_TYPE_P (TREE_TYPE (exp))
          && (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
        {
          push_obstacks_nochange ();
@@ -5714,7 +6022,7 @@ expand_expr (exp, target, tmode, modifier)
         memory protection).
 
         Aggregates are not checked here; they're handled elsewhere.  */
-      if (current_function && current_function_check_memory_usage
+      if (cfun && current_function_check_memory_usage
          && code == VAR_DECL
          && GET_CODE (DECL_RTL (exp)) == MEM
          && ! AGGREGATE_TYPE_P (TREE_TYPE (exp)))
@@ -5722,13 +6030,16 @@ expand_expr (exp, target, tmode, modifier)
          enum memory_use_mode memory_usage;
          memory_usage = get_memory_usage_from_modifier (modifier);
 
+         in_check_memory_usage = 1;
          if (memory_usage != MEMORY_USE_DONT)
-           emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
+           emit_library_call (chkr_check_addr_libfunc,
+                              LCT_CONST_MAKE_BLOCK, VOIDmode, 3,
                               XEXP (DECL_RTL (exp), 0), Pmode,
                               GEN_INT (int_size_in_bytes (type)),
                               TYPE_MODE (sizetype),
                               GEN_INT (memory_usage),
                               TYPE_MODE (integer_type_node));
+         in_check_memory_usage = 0;
        }
 
       /* ... fall through ...  */
@@ -5775,10 +6086,11 @@ expand_expr (exp, target, tmode, modifier)
            abort ();
          addr = XEXP (DECL_RTL (exp), 0);
          if (GET_CODE (addr) == MEM)
-           addr = gen_rtx_MEM (Pmode,
-                               fix_lexical_addr (XEXP (addr, 0), exp));
+           addr = change_address (addr, Pmode,
+                                  fix_lexical_addr (XEXP (addr, 0), exp));
          else
            addr = fix_lexical_addr (addr, exp);
+
          temp = change_address (DECL_RTL (exp), mode, addr);
        }
 
@@ -5811,8 +6123,7 @@ expand_expr (exp, target, tmode, modifier)
       if (temp != 0)
        {
          if (GET_CODE (temp) == MEM && GET_CODE (XEXP (temp, 0)) == REG)
-           mark_reg_pointer (XEXP (temp, 0),
-                             DECL_ALIGN (exp) / BITS_PER_UNIT);
+           mark_reg_pointer (XEXP (temp, 0), DECL_ALIGN (exp));
 
          return temp;
        }
@@ -5840,17 +6151,16 @@ expand_expr (exp, target, tmode, modifier)
 
     case INTEGER_CST:
       return immed_double_const (TREE_INT_CST_LOW (exp),
-                                TREE_INT_CST_HIGH (exp),
-                                mode);
+                                TREE_INT_CST_HIGH (exp), mode);
 
     case CONST_DECL:
       return expand_expr (DECL_INITIAL (exp), target, VOIDmode,
-                         EXPAND_MEMORY_USE_BAD);
+                         EXPAND_MEMORY_USE_BAD);
 
     case REAL_CST:
       /* If optimized, generate immediate CONST_DOUBLE
-        which will be turned into memory by reload if necessary. 
-     
+        which will be turned into memory by reload if necessary.
+
         We used to force a register so that loop.c could see it.  But
         this does not allow gen_* patterns to perform optimizations with
         the constants.  It also produces two insns in cases like "x = 1.0;".
@@ -5882,13 +6192,13 @@ expand_expr (exp, target, tmode, modifier)
     case EXPR_WITH_FILE_LOCATION:
       {
        rtx to_return;
-       char *saved_input_filename = input_filename;
+       const char *saved_input_filename = input_filename;
        int saved_lineno = lineno;
        input_filename = EXPR_WFL_FILENAME (exp);
        lineno = EXPR_WFL_LINENO (exp);
        if (EXPR_WFL_EMIT_LINE_NOTE (exp))
          emit_line_note (input_filename, lineno);
-       /* Possibly avoid switching back and force here */
+       /* Possibly avoid switching back and force here */
        to_return = expand_expr (EXPR_WFL_NODE (exp), target, tmode, modifier);
        input_filename = saved_input_filename;
        lineno = saved_lineno;
@@ -6004,7 +6314,7 @@ expand_expr (exp, target, tmode, modifier)
            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 
+              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 && object == 0;
@@ -6104,7 +6414,7 @@ expand_expr (exp, target, tmode, modifier)
 
        /* Need to open a binding contour here because
           if there are any cleanups they must be contained here.  */
-       expand_start_bindings (0);
+       expand_start_bindings (2);
 
        /* Mark the corresponding BLOCK for output in its proper place.  */
        if (TREE_OPERAND (exp, 2) != 0
@@ -6165,14 +6475,15 @@ expand_expr (exp, target, tmode, modifier)
                && ((mode == BLKmode
                     && ! (target != 0 && safe_from_p (target, exp, 1)))
                    || TREE_ADDRESSABLE (exp)
-                   || (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
-                       && (!MOVE_BY_PIECES_P 
-                             (TREE_INT_CST_LOW (TYPE_SIZE (type))/BITS_PER_UNIT,
-                            TYPE_ALIGN (type) / BITS_PER_UNIT))
+                   || (host_integerp (TYPE_SIZE_UNIT (type), 1)
+                       && (! MOVE_BY_PIECES_P
+                           (tree_low_cst (TYPE_SIZE_UNIT (type), 1),
+                            TYPE_ALIGN (type)))
                        && ! mostly_zeros_p (exp))))
               || (modifier == EXPAND_INITIALIZER && TREE_CONSTANT (exp)))
        {
          rtx constructor = output_constant_def (exp);
+
          if (modifier != EXPAND_CONST_ADDRESS
              && modifier != EXPAND_INITIALIZER
              && modifier != EXPAND_SUM
@@ -6206,33 +6517,32 @@ expand_expr (exp, target, tmode, modifier)
              RTX_UNCHANGING_P (target) = 1;
            }
 
-         store_constructor (exp, target, TYPE_ALIGN (TREE_TYPE (exp)), 0);
+         store_constructor (exp, target, TYPE_ALIGN (TREE_TYPE (exp)), 0,
+                            int_size_in_bytes (TREE_TYPE (exp)));
          return target;
        }
 
     case INDIRECT_REF:
       {
        tree exp1 = TREE_OPERAND (exp, 0);
-       tree exp2;
        tree index;
-       tree string = string_constant (exp1, &index);
-       int i;
+       tree string = string_constant (exp1, &index);
+
        /* Try to optimize reads from const strings.  */
        if (string
            && TREE_CODE (string) == STRING_CST
            && TREE_CODE (index) == INTEGER_CST
-           && !TREE_INT_CST_HIGH (index)
-           && (i = TREE_INT_CST_LOW (index)) < TREE_STRING_LENGTH (string)
+           && compare_tree_int (index, TREE_STRING_LENGTH (string)) < 0
            && GET_MODE_CLASS (mode) == MODE_INT
            && GET_MODE_SIZE (mode) == 1
            && modifier != EXPAND_MEMORY_USE_WO)
-         return GEN_INT (TREE_STRING_POINTER (string)[i]);
+         return
+           GEN_INT (TREE_STRING_POINTER (string)[TREE_INT_CST_LOW (index)]);
 
        op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
        op0 = memory_address (mode, op0);
 
-       if (current_function && current_function_check_memory_usage
+       if (cfun && current_function_check_memory_usage
            && ! AGGREGATE_TYPE_P (TREE_TYPE (exp)))
          {
            enum memory_use_mode memory_usage;
@@ -6241,9 +6551,9 @@ expand_expr (exp, target, tmode, modifier)
             if (memory_usage != MEMORY_USE_DONT)
              {
                in_check_memory_usage = 1;
-               emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
-                                  op0, Pmode,
-                                  GEN_INT (int_size_in_bytes (type)),
+               emit_library_call (chkr_check_addr_libfunc,
+                                  LCT_CONST_MAKE_BLOCK, VOIDmode, 3, op0,
+                                  Pmode, GEN_INT (int_size_in_bytes (type)),
                                   TYPE_MODE (sizetype),
                                   GEN_INT (memory_usage),
                                   TYPE_MODE (integer_type_node));
@@ -6252,19 +6562,7 @@ expand_expr (exp, target, tmode, modifier)
          }
 
        temp = gen_rtx_MEM (mode, op0);
-       /* If address was computed by addition,
-          mark this as an element of an aggregate.  */
-       if (TREE_CODE (exp1) == PLUS_EXPR
-           || (TREE_CODE (exp1) == SAVE_EXPR
-               && TREE_CODE (TREE_OPERAND (exp1, 0)) == PLUS_EXPR)
-           || AGGREGATE_TYPE_P (TREE_TYPE (exp))
-           || (TREE_CODE (exp1) == ADDR_EXPR
-               && (exp2 = TREE_OPERAND (exp1, 0))
-               && AGGREGATE_TYPE_P (TREE_TYPE (exp2))))
-         MEM_SET_IN_STRUCT_P (temp, 1);
-
-       MEM_VOLATILE_P (temp) = TREE_THIS_VOLATILE (exp) | flag_volatile;
-       MEM_ALIAS_SET (temp) = get_alias_set (exp);
+       set_mem_attributes (temp, exp, 0);
 
        /* It is incorrect to set RTX_UNCHANGING_P from TREE_READONLY
           here, because, in C and C++, the fact that a location is accessed
@@ -6272,6 +6570,14 @@ expand_expr (exp, target, tmode, modifier)
           never change.  Languages where it can never change should
           also set TREE_STATIC.  */
        RTX_UNCHANGING_P (temp) = TREE_READONLY (exp) & TREE_STATIC (exp);
+
+       /* If we are writing to this object and its type is a record with
+          readonly fields, we must mark it as readonly so it will
+          conflict with readonly references to those fields.  */
+       if (modifier == EXPAND_MEMORY_USE_WO
+           && TREE_CODE (type) == RECORD_TYPE && readonly_fields_p (type))
+         RTX_UNCHANGING_P (temp) = 1;
+
        return temp;
       }
 
@@ -6283,8 +6589,7 @@ expand_expr (exp, target, tmode, modifier)
        tree array = TREE_OPERAND (exp, 0);
        tree domain = TYPE_DOMAIN (TREE_TYPE (array));
        tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
-       tree index = TREE_OPERAND (exp, 1);
-       tree index_type = TREE_TYPE (index);
+       tree index = convert (sizetype, TREE_OPERAND (exp, 1));
        HOST_WIDE_INT i;
 
        /* Optimize the special-case of a zero lower bound.
@@ -6293,14 +6598,10 @@ expand_expr (exp, target, tmode, modifier)
           with constant folding.  (E.g. suppose the lower bound is 1,
           and its mode is QI.  Without the conversion,  (ARRAY
           +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
-          +INDEX), which becomes (ARRAY+255+INDEX).  Oops!)
-
-          But sizetype isn't quite right either (especially if
-          the lowbound is negative).  FIXME */
+          +INDEX), which becomes (ARRAY+255+INDEX).  Oops!)  */
 
        if (! integer_zerop (low_bound))
-         index = fold (build (MINUS_EXPR, index_type, index,
-                              convert (sizetype, low_bound)));
+         index = size_diffop (index, convert (sizetype, low_bound));
 
        /* Fold an expression like: "foo"[2].
           This is not done in fold so it won't happen inside &.
@@ -6309,33 +6610,35 @@ expand_expr (exp, target, tmode, modifier)
 
        if (TREE_CODE (array) == STRING_CST
            && TREE_CODE (index) == INTEGER_CST
-           && !TREE_INT_CST_HIGH (index)
-           && (i = TREE_INT_CST_LOW (index)) < TREE_STRING_LENGTH (array)
+           && compare_tree_int (index, TREE_STRING_LENGTH (array)) < 0
            && GET_MODE_CLASS (mode) == MODE_INT
            && GET_MODE_SIZE (mode) == 1)
-         return GEN_INT (TREE_STRING_POINTER (array)[i]);
+         return
+           GEN_INT (TREE_STRING_POINTER (array)[TREE_INT_CST_LOW (index)]);
 
        /* If this is a constant index into a constant array,
           just get the value from the array.  Handle both the cases when
           we have an explicit constructor and when our operand is a variable
           that was declared const.  */
 
-       if (TREE_CODE (array) == CONSTRUCTOR && ! TREE_SIDE_EFFECTS (array))
+       if (TREE_CODE (array) == CONSTRUCTOR && ! TREE_SIDE_EFFECTS (array)
+           && TREE_CODE (index) == INTEGER_CST
+           && 0 > compare_tree_int (index,
+                                    list_length (CONSTRUCTOR_ELTS
+                                                 (TREE_OPERAND (exp, 0)))))
          {
-           if (TREE_CODE (index) == INTEGER_CST
-               && TREE_INT_CST_HIGH (index) == 0)
-             {
-               tree elem = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0));
-
-               i = TREE_INT_CST_LOW (index);
-               while (elem && i--)
-                 elem = TREE_CHAIN (elem);
-               if (elem)
-                 return expand_expr (fold (TREE_VALUE (elem)), target,
-                                     tmode, ro_modifier);
-             }
+           tree elem;
+
+           for (elem = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)),
+                i = TREE_INT_CST_LOW (index);
+                elem != 0 && i != 0; i--, elem = TREE_CHAIN (elem))
+             ;
+
+           if (elem)
+             return expand_expr (fold (TREE_VALUE (elem)), target,
+                                 tmode, ro_modifier);
          }
-         
+
        else if (optimize >= 1
                 && TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
                 && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
@@ -6345,30 +6648,37 @@ expand_expr (exp, target, tmode, modifier)
              {
                tree init = DECL_INITIAL (array);
 
-               i = TREE_INT_CST_LOW (index);
                if (TREE_CODE (init) == CONSTRUCTOR)
                  {
-                   tree elem = CONSTRUCTOR_ELTS (init);
+                   tree elem;
+
+                   for (elem = CONSTRUCTOR_ELTS (init);
+                        (elem
+                         && !tree_int_cst_equal (TREE_PURPOSE (elem), index));
+                        elem = TREE_CHAIN (elem))
+                     ;
 
-                   while (elem
-                          && !tree_int_cst_equal (TREE_PURPOSE (elem), index))
-                     elem = TREE_CHAIN (elem);
                    if (elem)
                      return expand_expr (fold (TREE_VALUE (elem)), target,
                                          tmode, ro_modifier);
                  }
                else if (TREE_CODE (init) == STRING_CST
-                        && TREE_INT_CST_HIGH (index) == 0
-                        && (TREE_INT_CST_LOW (index)
-                            < TREE_STRING_LENGTH (init)))
-                 return (GEN_INT
-                         (TREE_STRING_POINTER
-                          (init)[TREE_INT_CST_LOW (index)]));
+                        && 0 > compare_tree_int (index,
+                                                 TREE_STRING_LENGTH (init)))
+                 {
+                   tree type = TREE_TYPE (TREE_TYPE (init));
+                   enum machine_mode mode = TYPE_MODE (type);
+
+                   if (GET_MODE_CLASS (mode) == MODE_INT
+                       && GET_MODE_SIZE (mode) == 1)
+                     return (GEN_INT
+                             (TREE_STRING_POINTER
+                              (init)[TREE_INT_CST_LOW (index)]));
+                 }
              }
          }
       }
-
-      /* ... fall through ... */
+      /* Fall through.  */
 
     case COMPONENT_REF:
     case BIT_FIELD_REF:
@@ -6398,10 +6708,11 @@ expand_expr (exp, target, tmode, modifier)
                        && (GET_MODE_BITSIZE (DECL_MODE (TREE_PURPOSE (elt)))
                            <= HOST_BITS_PER_WIDE_INT))))
              {
-               op0 =  expand_expr (TREE_VALUE (elt), target, tmode, modifier);
+               op0 = expand_expr (TREE_VALUE (elt), target, tmode, modifier);
                if (DECL_BIT_FIELD (TREE_PURPOSE (elt)))
                  {
-                   int bitsize = DECL_FIELD_SIZE (TREE_PURPOSE (elt));
+                   HOST_WIDE_INT bitsize
+                     = TREE_INT_CST_LOW (DECL_SIZE (TREE_PURPOSE (elt)));
 
                    if (TREE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
                      {
@@ -6429,11 +6740,10 @@ expand_expr (exp, target, tmode, modifier)
 
       {
        enum machine_mode mode1;
-       int bitsize;
-       int bitpos;
+       HOST_WIDE_INT bitsize, bitpos;
        tree offset;
        int volatilep = 0;
-       int alignment;
+       unsigned int alignment;
        tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
                                        &mode1, &unsignedp, &volatilep,
                                        &alignment);
@@ -6447,22 +6757,24 @@ expand_expr (exp, target, tmode, modifier)
        /* If TEM's type is a union of variable size, pass TARGET to the inner
           computation, since it will need a temporary and TARGET is known
           to have to do.  This occurs in unchecked conversion in Ada.  */
-  
+
        op0 = expand_expr (tem,
                           (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
                            && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
                                != INTEGER_CST)
                            ? target : NULL_RTX),
                           VOIDmode,
-                          modifier == EXPAND_INITIALIZER
+                          (modifier == EXPAND_INITIALIZER
+                           || modifier == EXPAND_CONST_ADDRESS)
                           ? modifier : EXPAND_NORMAL);
 
        /* If this is a constant, put it into a register if it is a
-          legitimate constant and memory if it isn't.  */
+          legitimate constant and OFFSET is 0 and memory if it isn't.  */
        if (CONSTANT_P (op0))
          {
            enum machine_mode mode = TYPE_MODE (TREE_TYPE (tem));
-           if (mode != BLKmode && LEGITIMATE_CONSTANT_P (op0))
+           if (mode != BLKmode && LEGITIMATE_CONSTANT_P (op0)
+               && offset == 0)
              op0 = force_reg (mode, op0);
            else
              op0 = validize_mem (force_const_mem (mode, op0));
@@ -6472,6 +6784,20 @@ expand_expr (exp, target, tmode, modifier)
          {
            rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
 
+           /* If this object is in memory, put it into a register.
+              This case can't occur in C, but can in Ada if we have
+              unchecked conversion of an expression from a scalar type to
+              an array or record type.  */
+           if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
+               || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
+             {
+               rtx memloc = assign_temp (TREE_TYPE (tem), 1, 1, 1);
+
+               mark_temp_addr_taken (memloc);
+               emit_move_insn (memloc, op0);
+               op0 = memloc;
+             }
+
            if (GET_CODE (op0) != MEM)
              abort ();
 
@@ -6484,15 +6810,15 @@ expand_expr (exp, target, tmode, modifier)
 #endif
              }
 
-           /* A constant address in TO_RTX can have VOIDmode, we must not try
+           /* 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
                && GET_MODE (XEXP (op0, 0)) != VOIDmode
-               && bitsize
-               && (bitpos % bitsize) == 0 
+               && bitsize != 0
+               && (bitpos % bitsize) == 0
                && (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
-               && (alignment * BITS_PER_UNIT) == GET_MODE_ALIGNMENT (mode1))
+               && alignment == GET_MODE_ALIGNMENT (mode1))
              {
                rtx temp = change_address (op0, mode1,
                                           plus_constant (XEXP (op0, 0),
@@ -6507,7 +6833,6 @@ expand_expr (exp, target, tmode, modifier)
                bitpos = 0;
              }
 
-
            op0 = change_address (op0, VOIDmode,
                                  gen_rtx_PLUS (ptr_mode, XEXP (op0, 0),
                                                force_reg (ptr_mode,
@@ -6522,8 +6847,9 @@ expand_expr (exp, target, tmode, modifier)
          }
 
        /* Check the access.  */
-       if (current_function_check_memory_usage && GET_CODE (op0) == MEM)
-          {
+       if (cfun != 0 && current_function_check_memory_usage
+           && GET_CODE (op0) == MEM)
+         {
            enum memory_use_mode memory_usage;
            memory_usage = get_memory_usage_from_modifier (modifier);
 
@@ -6536,13 +6862,15 @@ expand_expr (exp, target, tmode, modifier)
                size = (bitpos % BITS_PER_UNIT) + bitsize + BITS_PER_UNIT - 1;
 
                /* Check the access right of the pointer.  */
+               in_check_memory_usage = 1;
                if (size > BITS_PER_UNIT)
-                 emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
-                                    to, Pmode,
-                                    GEN_INT (size / BITS_PER_UNIT),
+                 emit_library_call (chkr_check_addr_libfunc,
+                                    LCT_CONST_MAKE_BLOCK, VOIDmode, 3, to,
+                                    Pmode, GEN_INT (size / BITS_PER_UNIT),
                                     TYPE_MODE (sizetype),
-                                    GEN_INT (memory_usage), 
+                                    GEN_INT (memory_usage),
                                     TYPE_MODE (integer_type_node));
+               in_check_memory_usage = 0;
              }
          }
 
@@ -6563,13 +6891,32 @@ expand_expr (exp, target, tmode, modifier)
                     && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
                    /* If the field isn't aligned enough to fetch as a memref,
                       fetch it as a bit field.  */
-                   || (SLOW_UNALIGNED_ACCESS
-                       && ((TYPE_ALIGN (TREE_TYPE (tem)) < (unsigned int) GET_MODE_ALIGNMENT (mode))
-                           || (bitpos % GET_MODE_ALIGNMENT (mode) != 0))))))
+                   || (mode1 != BLKmode
+                       && SLOW_UNALIGNED_ACCESS (mode1, alignment)
+                       && ((TYPE_ALIGN (TREE_TYPE (tem))
+                            < GET_MODE_ALIGNMENT (mode))
+                           || (bitpos % GET_MODE_ALIGNMENT (mode) != 0)))
+                   /* If the type and the field are a constant size and the
+                      size of the type isn't the same size as the bitfield,
+                      we must use bitfield operations.  */
+                   || ((bitsize >= 0
+                        && (TREE_CODE (TYPE_SIZE (TREE_TYPE (exp)))
+                            == INTEGER_CST)
+                        && 0 != compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)),
+                                                  bitsize)))))
+           || (modifier != EXPAND_CONST_ADDRESS
+               && modifier != EXPAND_INITIALIZER
+               && mode == BLKmode
+               && SLOW_UNALIGNED_ACCESS (mode, alignment)
+               && (TYPE_ALIGN (type) > alignment
+                   || bitpos % TYPE_ALIGN (type) != 0)))
          {
            enum machine_mode ext_mode = mode;
 
-           if (ext_mode == BLKmode)
+           if (ext_mode == BLKmode
+               && ! (target != 0 && GET_CODE (op0) == MEM
+                     && GET_CODE (target) == MEM
+                     && bitpos % BITS_PER_UNIT == 0))
              ext_mode = mode_for_size (bitsize, MODE_INT, 1);
 
            if (ext_mode == BLKmode)
@@ -6588,10 +6935,11 @@ expand_expr (exp, target, tmode, modifier)
                  target = assign_temp (type, 0, 1, 1);
 
                emit_block_move (target, op0,
-                                GEN_INT ((bitsize + BITS_PER_UNIT - 1)
-                                         / BITS_PER_UNIT),
-                                1);
-               
+                                bitsize == -1 ? expr_size  (exp)
+                                : GEN_INT ((bitsize + BITS_PER_UNIT - 1)
+                                           / BITS_PER_UNIT),
+                                BITS_PER_UNIT);
+
                return target;
              }
 
@@ -6638,20 +6986,23 @@ expand_expr (exp, target, tmode, modifier)
        /* Get a reference to just this component.  */
        if (modifier == EXPAND_CONST_ADDRESS
            || modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
-         op0 = gen_rtx_MEM (mode1, plus_constant (XEXP (op0, 0),
-                                                  (bitpos / BITS_PER_UNIT)));
+         {
+           rtx new = gen_rtx_MEM (mode1,
+                                  plus_constant (XEXP (op0, 0),
+                                                 (bitpos / BITS_PER_UNIT)));
+
+           MEM_COPY_ATTRIBUTES (new, op0);
+           op0 = new;
+         }
        else
          op0 = change_address (op0, mode1,
                                plus_constant (XEXP (op0, 0),
                                               (bitpos / BITS_PER_UNIT)));
 
-       if (GET_CODE (op0) == MEM)
-         MEM_ALIAS_SET (op0) = get_alias_set (exp);
-
+       set_mem_attributes (op0, exp, 0);
        if (GET_CODE (XEXP (op0, 0)) == REG)
          mark_reg_pointer (XEXP (op0, 0), alignment);
 
-       MEM_SET_IN_STRUCT_P (op0, 1);
        MEM_VOLATILE_P (op0) |= volatilep;
        if (mode == mode1 || mode1 == BLKmode || mode1 == tmode
            || modifier == EXPAND_CONST_ADDRESS
@@ -6738,7 +7089,7 @@ expand_expr (exp, target, tmode, modifier)
           of the set.  */
        if (GET_CODE (lo_r) == CONST_INT)
          rlow = GEN_INT (INTVAL (lo_r)
-                         & ~ ((HOST_WIDE_INT) 1 << BITS_PER_UNIT));
+                         & ~((HOST_WIDE_INT) 1 << BITS_PER_UNIT));
        else
          rlow = expand_binop (index_mode, and_optab, lo_r,
                               GEN_INT (~((HOST_WIDE_INT) 1 << BITS_PER_UNIT)),
@@ -6757,7 +7108,7 @@ expand_expr (exp, target, tmode, modifier)
                                             setaddr, NULL_RTX, iunsignedp,
                                             OPTAB_LIB_WIDEN));
 
-       /* Extract the bit we want to examine */
+       /* Extract the bit we want to examine */
        bit = expand_shift (RSHIFT_EXPR, byte_mode,
                            gen_rtx_MEM (byte_mode, addr),
                            make_tree (TREE_TYPE (index), rem),
@@ -6793,7 +7144,7 @@ expand_expr (exp, target, tmode, modifier)
       {
        /* Start a new binding layer that will keep track of all cleanup
           actions to be performed.  */
-       expand_start_bindings (0);
+       expand_start_bindings (2);
 
        target_temp_slot_level = temp_slot_level;
 
@@ -6812,7 +7163,13 @@ expand_expr (exp, target, tmode, modifier)
          && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
              == FUNCTION_DECL)
          && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
-       return expand_builtin (exp, target, subtarget, tmode, ignore);
+        {
+         if (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+             == BUILT_IN_FRONTEND)
+           return (*lang_expand_expr) (exp, original_target, tmode, modifier);
+         else
+           return expand_builtin (exp, target, subtarget, tmode, ignore);
+       }
 
       /* If this call was expanded already by preexpand_calls,
         just return the result we got.  */
@@ -6825,9 +7182,22 @@ expand_expr (exp, target, tmode, modifier)
     case NOP_EXPR:
     case CONVERT_EXPR:
     case REFERENCE_EXPR:
+      if (TREE_OPERAND (exp, 0) == error_mark_node)
+       return const0_rtx;
+
       if (TREE_CODE (type) == UNION_TYPE)
        {
          tree valtype = TREE_TYPE (TREE_OPERAND (exp, 0));
+
+         /* If both input and output are BLKmode, this conversion
+            isn't actually doing anything unless we need to make the
+            alignment stricter.  */
+         if (mode == BLKmode && TYPE_MODE (valtype) == BLKmode
+             && (TYPE_ALIGN (type) <= TYPE_ALIGN (valtype)
+                 || TYPE_ALIGN (type) >= BIGGEST_ALIGNMENT))
+           return expand_expr (TREE_OPERAND (exp, 0), target, tmode,
+                               modifier);
+
          if (target == 0)
            {
              if (mode != BLKmode)
@@ -6843,11 +7213,14 @@ expand_expr (exp, target, tmode, modifier)
 
          else if (GET_CODE (target) == REG)
            /* Store this field into a union of the proper type.  */
-           store_field (target, GET_MODE_BITSIZE (TYPE_MODE (valtype)), 0,
-                        TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
-                        VOIDmode, 0, 1,
-                        int_size_in_bytes (TREE_TYPE (TREE_OPERAND (exp, 0))),
-                        0);
+           store_field (target,
+                        MIN ((int_size_in_bytes (TREE_TYPE
+                                                 (TREE_OPERAND (exp, 0)))
+                              * BITS_PER_UNIT),
+                             GET_MODE_BITSIZE (mode)),
+                        0, TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
+                        VOIDmode, 0, BITS_PER_UNIT,
+                        int_size_in_bytes (type), 0);
          else
            abort ();
 
@@ -7032,7 +7405,7 @@ expand_expr (exp, target, tmode, modifier)
          op0 = eliminate_constant_term (op0, &constant_term);
 
          /* CONSTANT_TERM and XEXP (op1, 1) are known to be constant, so
-            their sum should be a constant.  Form it into OP1, since the 
+            their sum should be a constant.  Form it into OP1, since the
             result we want will then be OP0 + OP1.  */
 
          temp = simplify_binary_operation (PLUS, mode, constant_term,
@@ -7078,21 +7451,11 @@ expand_expr (exp, target, tmode, modifier)
          tree negated = fold (build1 (NEGATE_EXPR, type,
                                       TREE_OPERAND (exp, 1)));
 
-         /* Deal with the case where we can't negate the constant
-            in TYPE.  */
          if (TREE_UNSIGNED (type) || TREE_OVERFLOW (negated))
-           {
-             tree newtype = signed_type (type);
-             tree newop0 = convert (newtype, TREE_OPERAND (exp, 0));
-             tree newop1 = convert (newtype, TREE_OPERAND (exp, 1));
-             tree newneg = fold (build1 (NEGATE_EXPR, newtype, newop1));
-
-             if (! TREE_OVERFLOW (newneg))
-               return expand_expr (convert (type, 
-                                            build (PLUS_EXPR, newtype,
-                                                   newop0, newneg)),
-                                   target, tmode, ro_modifier);
-           }
+           /* If we can't negate the constant in TYPE, leave it alone and
+              expand_binop will negate it for us.  We used to try to do it
+              here in the signed version of TYPE, but that doesn't work
+              on POINTER_TYPEs.  */;
          else
            {
              exp = build (PLUS_EXPR, type, TREE_OPERAND (exp, 0), negated);
@@ -7202,8 +7565,10 @@ expand_expr (exp, target, tmode, modifier)
                  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);
+                   op1 = convert_modes (innermode, mode,
+                                        expand_expr (TREE_OPERAND (exp, 1),
+                                                     NULL_RTX, VOIDmode, 0),
+                                        unsignedp);
                  else
                    op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
                                       NULL_RTX, VOIDmode, 0);
@@ -7327,7 +7692,7 @@ expand_expr (exp, target, tmode, modifier)
 
       /* At this point, a MEM target is no longer useful; we will get better
         code without it.  */
-        
+
       if (GET_CODE (target) == MEM)
        target = gen_reg_rtx (mode);
 
@@ -7338,7 +7703,8 @@ expand_expr (exp, target, tmode, modifier)
 
       /* If this mode is an integer too wide to compare properly,
         compare word by word.  Rely on cse to optimize constant cases.  */
-      if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode))
+      if (GET_MODE_CLASS (mode) == MODE_INT
+         && ! can_compare_p (GE, mode, ccp_jump))
        {
          if (code == MAX_EXPR)
            do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type),
@@ -7419,6 +7785,13 @@ expand_expr (exp, target, tmode, modifier)
     case GE_EXPR:
     case EQ_EXPR:
     case NE_EXPR:
+    case UNORDERED_EXPR:
+    case ORDERED_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
       preexpand_calls (exp);
       temp = do_store_flag (exp, target, tmode != VOIDmode ? tmode : mode, 0);
       if (temp != 0)
@@ -7574,7 +7947,7 @@ expand_expr (exp, target, tmode, modifier)
 
        /* If we are not to produce a result, we have no target.  Otherwise,
           if a target was specified use it; it will not be used as an
-          intermediate target unless it is safe.  If no target, use a 
+          intermediate target unless it is safe.  If no target, use a
           temporary.  */
 
        if (ignore)
@@ -7652,7 +8025,7 @@ expand_expr (exp, target, tmode, modifier)
              TREE_OPERAND (exp, 0)
                = invert_truthvalue (TREE_OPERAND (exp, 0));
          }
-           
+
        do_pending_stack_adjust ();
        NO_DEFER_POP;
        op0 = gen_label_rtx ();
@@ -7709,7 +8082,8 @@ expand_expr (exp, target, tmode, modifier)
                     || TREE_CODE (TREE_OPERAND (exp, 1)) == SAVE_EXPR)
                 && safe_from_p (temp, TREE_OPERAND (exp, 2), 1))
          {
-           if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
+           if (GET_CODE (temp) == REG
+               && REGNO (temp) < FIRST_PSEUDO_REGISTER)
              temp = gen_reg_rtx (mode);
            store_expr (TREE_OPERAND (exp, 1), temp, 0);
            jumpif (TREE_OPERAND (exp, 0), op0);
@@ -7727,7 +8101,8 @@ expand_expr (exp, target, tmode, modifier)
                     || TREE_CODE (TREE_OPERAND (exp, 2)) == SAVE_EXPR)
                 && safe_from_p (temp, TREE_OPERAND (exp, 1), 1))
          {
-           if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
+           if (GET_CODE (temp) == REG
+               && REGNO (temp) < FIRST_PSEUDO_REGISTER)
              temp = gen_reg_rtx (mode);
            store_expr (TREE_OPERAND (exp, 2), temp, 0);
            jumpifnot (TREE_OPERAND (exp, 0), op0);
@@ -7742,11 +8117,11 @@ expand_expr (exp, target, tmode, modifier)
            jumpifnot (TREE_OPERAND (exp, 0), op0);
 
            start_cleanup_deferral ();
-           
+
            /* One branch of the cond can be void, if it never returns. For
-               example A ? throw : E  */
+              example A ? throw : E  */
            if (temp != 0
-               && TREE_TYPE (TREE_OPERAND (exp, 1)) != void_type_node)
+               && TREE_TYPE (TREE_OPERAND (exp, 1)) != void_type_node)
              store_expr (TREE_OPERAND (exp, 1), temp, 0);
            else
              expand_expr (TREE_OPERAND (exp, 1),
@@ -7758,7 +8133,7 @@ expand_expr (exp, target, tmode, modifier)
            emit_label (op0);
            start_cleanup_deferral ();
            if (temp != 0
-               && TREE_TYPE (TREE_OPERAND (exp, 2)) != void_type_node)
+               && TREE_TYPE (TREE_OPERAND (exp, 2)) != void_type_node)
              store_expr (TREE_OPERAND (exp, 2), temp, 0);
            else
              expand_expr (TREE_OPERAND (exp, 2),
@@ -7795,6 +8170,11 @@ expand_expr (exp, target, tmode, modifier)
        if (! ignore)
          target = original_target;
 
+       /* Set this here so that if we get a target that refers to a
+          register variable that's already been used, put_reg_into_stack
+          knows that it should fix up those uses.  */
+       TREE_USED (slot) = 1;
+
        if (target == 0)
          {
            if (DECL_RTL (slot) != 0)
@@ -7812,10 +8192,7 @@ expand_expr (exp, target, tmode, modifier)
                preserve_temp_slots (target);
                DECL_RTL (slot) = target;
                if (TREE_ADDRESSABLE (slot))
-                 {
-                   TREE_ADDRESSABLE (slot) = 0;
-                   mark_addressable (slot);
-                 }
+                 put_var_into_stack (slot);
 
                /* Since SLOT is not known to the called function
                   to belong to its stack frame, we must build an explicit
@@ -7840,12 +8217,12 @@ expand_expr (exp, target, tmode, modifier)
               not target that we were passed in, as our target
               parameter is only a hint.  */
            if (DECL_RTL (slot) != 0)
-              {
-                target = DECL_RTL (slot);
-                /* If we have already expanded the slot, so don't do
+             {
+               target = DECL_RTL (slot);
+               /* If we have already expanded the slot, so don't do
                    it again.  (mrs)  */
-                if (TREE_OPERAND (exp, 1) == NULL_TREE)
-                  return target;
+               if (TREE_OPERAND (exp, 1) == NULL_TREE)
+                 return target;
              }
            else
              {
@@ -7853,10 +8230,7 @@ expand_expr (exp, target, tmode, modifier)
                /* If we must have an addressable slot, then make sure that
                   the RTL that we just stored in slot is OK.  */
                if (TREE_ADDRESSABLE (slot))
-                 {
-                   TREE_ADDRESSABLE (slot) = 0;
-                   mark_addressable (slot);
-                 }
+                 put_var_into_stack (slot);
              }
          }
 
@@ -7864,11 +8238,10 @@ expand_expr (exp, target, tmode, modifier)
        /* Mark it as expanded.  */
        TREE_OPERAND (exp, 1) = NULL_TREE;
 
-       TREE_USED (slot) = 1;
        store_expr (exp1, target, 0);
 
        expand_decl_cleanup (NULL_TREE, cleanups);
-       
+
        return target;
       }
 
@@ -7929,8 +8302,8 @@ expand_expr (exp, target, tmode, modifier)
                || TREE_CODE (rhs) == BIT_AND_EXPR)
            && TREE_OPERAND (rhs, 0) == lhs
            && TREE_CODE (TREE_OPERAND (rhs, 1)) == COMPONENT_REF
-           && TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (lhs, 1))) == 1
-           && TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (TREE_OPERAND (rhs, 1), 1))) == 1)
+           && integer_onep (DECL_SIZE (TREE_OPERAND (lhs, 1)))
+           && integer_onep (DECL_SIZE (TREE_OPERAND (TREE_OPERAND (rhs, 1), 1))))
          {
            rtx label = gen_label_rtx ();
 
@@ -8041,7 +8414,7 @@ expand_expr (exp, target, tmode, modifier)
 
          if (GET_CODE (op0) != MEM)
            abort ();
-  
+
          if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
            {
              temp = XEXP (op0, 0);
@@ -8061,7 +8434,7 @@ expand_expr (exp, target, tmode, modifier)
 
       if (GET_CODE (op0) == REG
          && ! REG_USERVAR_P (op0))
-       mark_reg_pointer (op0, TYPE_ALIGN (TREE_TYPE (type)) / BITS_PER_UNIT);
+       mark_reg_pointer (op0, TYPE_ALIGN (TREE_TYPE (type)));
 
       /* If we might have had a temp slot, add an equivalent address
         for it.  */
@@ -8116,7 +8489,7 @@ expand_expr (exp, target, tmode, modifier)
     case REALPART_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
       return gen_realpart (mode, op0);
-      
+
     case IMAGPART_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
       return gen_imagpart (mode, op0);
@@ -8126,12 +8499,12 @@ expand_expr (exp, target, tmode, modifier)
        enum machine_mode partmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
        rtx imag_t;
        rtx insns;
-       
-       op0  = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
+
+       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
 
        if (! target)
          target = gen_reg_rtx (mode);
-                                                                   
+
        start_sequence ();
 
        /* Store the realpart and the negated imagpart to target.  */
@@ -8140,14 +8513,14 @@ expand_expr (exp, target, tmode, modifier)
 
        imag_t = gen_imagpart (partmode, target);
        temp = expand_unop (partmode, neg_optab,
-                              gen_imagpart (partmode, op0), imag_t, 0);
+                           gen_imagpart (partmode, op0), imag_t, 0);
        if (temp != imag_t)
          emit_move_insn (imag_t, temp);
 
        insns = get_insns ();
        end_sequence ();
 
-       /* Conjugate should appear as a single unit 
+       /* Conjugate should appear as a single unit
           If TARGET is a CONCAT, we got insns like RD = RS, ID = - IS,
           each with a separate pseudo as destination.
           It's not correct for flow to treat them as a unit.  */
@@ -8185,7 +8558,7 @@ expand_expr (exp, target, tmode, modifier)
 
        /* Start a new binding layer that will keep track of all cleanup
           actions to be performed.  */
-       expand_start_bindings (0);
+       expand_start_bindings (2);
 
        target_temp_slot_level = temp_slot_level;
 
@@ -8202,12 +8575,13 @@ expand_expr (exp, target, tmode, modifier)
        return op0;
       }
 
-      case GOTO_SUBROUTINE_EXPR:
+    case GOTO_SUBROUTINE_EXPR:
       {
        rtx subr = (rtx) TREE_OPERAND (exp, 0);
        rtx return_link = *(rtx *) &TREE_OPERAND (exp, 1);
        rtx return_address = gen_label_rtx ();
-       emit_move_insn (return_link, gen_rtx_LABEL_REF (Pmode, return_address));
+       emit_move_insn (return_link,
+                       gen_rtx_LABEL_REF (Pmode, return_address));
        emit_jump (subr);
        emit_label (return_address);
        return const0_rtx;
@@ -8250,8 +8624,319 @@ expand_expr (exp, target, tmode, modifier)
   return temp;
 }
 \f
-/* Return the tree node and offset if a given argument corresponds to
-   a string constant.  */
+/* Similar to expand_expr, except that we don't specify a target, target
+   mode, or modifier and we return the alignment of the inner type.  This is
+   used in cases where it is not necessary to align the result to the
+   alignment of its type as long as we know the alignment of the result, for
+   example for comparisons of BLKmode values.  */
+
+static rtx
+expand_expr_unaligned (exp, palign)
+     register tree exp;
+     unsigned int *palign;
+{
+  register rtx op0;
+  tree type = TREE_TYPE (exp);
+  register enum machine_mode mode = TYPE_MODE (type);
+
+  /* Default the alignment we return to that of the type.  */
+  *palign = TYPE_ALIGN (type);
+
+  /* The only cases in which we do anything special is if the resulting mode
+     is BLKmode.  */
+  if (mode != BLKmode)
+    return expand_expr (exp, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+
+  switch (TREE_CODE (exp))
+    {
+    case CONVERT_EXPR:
+    case NOP_EXPR:
+    case NON_LVALUE_EXPR:
+      /* Conversions between BLKmode values don't change the underlying
+         alignment or value.  */
+      if (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == BLKmode)
+       return expand_expr_unaligned (TREE_OPERAND (exp, 0), palign);
+      break;
+
+    case ARRAY_REF:
+      /* Much of the code for this case is copied directly from expand_expr.
+        We need to duplicate it here because we will do something different
+        in the fall-through case, so we need to handle the same exceptions
+        it does.  */
+      {
+       tree array = TREE_OPERAND (exp, 0);
+       tree domain = TYPE_DOMAIN (TREE_TYPE (array));
+       tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
+       tree index = convert (sizetype, TREE_OPERAND (exp, 1));
+       HOST_WIDE_INT i;
+
+       if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) != ARRAY_TYPE)
+         abort ();
+
+       /* Optimize the special-case of a zero lower bound.
+
+          We convert the low_bound to sizetype to avoid some problems
+          with constant folding.  (E.g. suppose the lower bound is 1,
+          and its mode is QI.  Without the conversion,  (ARRAY
+          +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
+          +INDEX), which becomes (ARRAY+255+INDEX).  Oops!)  */
+
+       if (! integer_zerop (low_bound))
+         index = size_diffop (index, convert (sizetype, low_bound));
+
+       /* If this is a constant index into a constant array,
+          just get the value from the array.  Handle both the cases when
+          we have an explicit constructor and when our operand is a variable
+          that was declared const.  */
+
+       if (TREE_CODE (array) == CONSTRUCTOR && ! TREE_SIDE_EFFECTS (array)
+           && 0 > compare_tree_int (index,
+                                    list_length (CONSTRUCTOR_ELTS
+                                                 (TREE_OPERAND (exp, 0)))))
+         {
+           tree elem;
+
+           for (elem = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)),
+                i = TREE_INT_CST_LOW (index);
+                elem != 0 && i != 0; i--, elem = TREE_CHAIN (elem))
+             ;
+
+           if (elem)
+             return expand_expr_unaligned (fold (TREE_VALUE (elem)), palign);
+         }
+
+       else if (optimize >= 1
+                && TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
+                && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
+                && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK)
+         {
+           if (TREE_CODE (index) == INTEGER_CST)
+             {
+               tree init = DECL_INITIAL (array);
+
+               if (TREE_CODE (init) == CONSTRUCTOR)
+                 {
+                   tree elem;
+
+                   for (elem = CONSTRUCTOR_ELTS (init);
+                        ! tree_int_cst_equal (TREE_PURPOSE (elem), index);
+                        elem = TREE_CHAIN (elem))
+                     ;
+
+                   if (elem)
+                     return expand_expr_unaligned (fold (TREE_VALUE (elem)),
+                                                   palign);
+                 }
+             }
+         }
+      }
+      /* Fall through.  */
+
+    case COMPONENT_REF:
+    case BIT_FIELD_REF:
+      /* If the operand is a CONSTRUCTOR, we can just extract the
+        appropriate field if it is present.  Don't do this if we have
+        already written the data since we want to refer to that copy
+        and varasm.c assumes that's what we'll do.  */
+      if (TREE_CODE (exp) != ARRAY_REF
+         && TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR
+         && TREE_CST_RTL (TREE_OPERAND (exp, 0)) == 0)
+       {
+         tree elt;
+
+         for (elt = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); elt;
+              elt = TREE_CHAIN (elt))
+           if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1))
+             /* Note that unlike the case in expand_expr, we know this is
+                BLKmode and hence not an integer.  */
+             return expand_expr_unaligned (TREE_VALUE (elt), palign);
+       }
+
+      {
+       enum machine_mode mode1;
+       HOST_WIDE_INT bitsize, bitpos;
+       tree offset;
+       int volatilep = 0;
+       unsigned int alignment;
+       int unsignedp;
+       tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
+                                       &mode1, &unsignedp, &volatilep,
+                                       &alignment);
+
+       /* If we got back the original object, something is wrong.  Perhaps
+          we are evaluating an expression too early.  In any event, don't
+          infinitely recurse.  */
+       if (tem == exp)
+         abort ();
+
+       op0 = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+
+       /* If this is a constant, put it into a register if it is a
+          legitimate constant and OFFSET is 0 and memory if it isn't.  */
+       if (CONSTANT_P (op0))
+         {
+           enum machine_mode inner_mode = TYPE_MODE (TREE_TYPE (tem));
+
+           if (inner_mode != BLKmode && LEGITIMATE_CONSTANT_P (op0)
+               && offset == 0)
+             op0 = force_reg (inner_mode, op0);
+           else
+             op0 = validize_mem (force_const_mem (inner_mode, op0));
+         }
+
+       if (offset != 0)
+         {
+           rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
+
+           /* If this object is in a register, put it into memory.
+              This case can't occur in C, but can in Ada if we have
+              unchecked conversion of an expression from a scalar type to
+              an array or record type.  */
+           if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
+               || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
+             {
+               rtx memloc = assign_temp (TREE_TYPE (tem), 1, 1, 1);
+
+               mark_temp_addr_taken (memloc);
+               emit_move_insn (memloc, op0);
+               op0 = memloc;
+             }
+
+           if (GET_CODE (op0) != MEM)
+             abort ();
+
+           if (GET_MODE (offset_rtx) != ptr_mode)
+             {
+#ifdef POINTERS_EXTEND_UNSIGNED
+               offset_rtx = convert_memory_address (ptr_mode, offset_rtx);
+#else
+               offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
+#endif
+             }
+
+           op0 = change_address (op0, VOIDmode,
+                                 gen_rtx_PLUS (ptr_mode, XEXP (op0, 0),
+                                               force_reg (ptr_mode,
+                                                          offset_rtx)));
+         }
+
+       /* Don't forget about volatility even if this is a bitfield.  */
+       if (GET_CODE (op0) == MEM && volatilep && ! MEM_VOLATILE_P (op0))
+         {
+           op0 = copy_rtx (op0);
+           MEM_VOLATILE_P (op0) = 1;
+         }
+
+       /* Check the access.  */
+       if (current_function_check_memory_usage && GET_CODE (op0) == MEM)
+         {
+           rtx to;
+           int size;
+
+           to = plus_constant (XEXP (op0, 0), (bitpos / BITS_PER_UNIT));
+           size = (bitpos % BITS_PER_UNIT) + bitsize + BITS_PER_UNIT - 1;
+
+           /* Check the access right of the pointer.  */
+           in_check_memory_usage = 1;
+           if (size > BITS_PER_UNIT)
+             emit_library_call (chkr_check_addr_libfunc,
+                                LCT_CONST_MAKE_BLOCK, VOIDmode, 3,
+                                to, ptr_mode, GEN_INT (size / BITS_PER_UNIT),
+                                TYPE_MODE (sizetype),
+                                GEN_INT (MEMORY_USE_RO),
+                                TYPE_MODE (integer_type_node));
+           in_check_memory_usage = 0;
+         }
+
+       /* In cases where an aligned union has an unaligned object
+          as a field, we might be extracting a BLKmode value from
+          an integer-mode (e.g., SImode) object.  Handle this case
+          by doing the extract into an object as wide as the field
+          (which we know to be the width of a basic mode), then
+          storing into memory, and changing the mode to BLKmode.
+          If we ultimately want the address (EXPAND_CONST_ADDRESS or
+          EXPAND_INITIALIZER), then we must not copy to a temporary.  */
+       if (mode1 == VOIDmode
+           || GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
+           || (SLOW_UNALIGNED_ACCESS (mode1, alignment)
+               && (TYPE_ALIGN (type) > alignment
+                   || bitpos % TYPE_ALIGN (type) != 0)))
+         {
+           enum machine_mode ext_mode = mode_for_size (bitsize, MODE_INT, 1);
+
+           if (ext_mode == BLKmode)
+             {
+               /* In this case, BITPOS must start at a byte boundary.  */
+               if (GET_CODE (op0) != MEM
+                   || bitpos % BITS_PER_UNIT != 0)
+                 abort ();
+
+               op0 = change_address (op0, VOIDmode,
+                                     plus_constant (XEXP (op0, 0),
+                                                    bitpos / BITS_PER_UNIT));
+             }
+           else
+             {
+               rtx new = assign_stack_temp (ext_mode,
+                                            bitsize / BITS_PER_UNIT, 0);
+
+               op0 = extract_bit_field (validize_mem (op0), bitsize, bitpos,
+                                        unsignedp, NULL_RTX, ext_mode,
+                                        ext_mode, alignment,
+                                        int_size_in_bytes (TREE_TYPE (tem)));
+
+               /* If the result is a record type and BITSIZE is narrower than
+                  the mode of OP0, an integral mode, and this is a big endian
+                  machine, we must put the field into the high-order bits.  */
+               if (TREE_CODE (type) == RECORD_TYPE && BYTES_BIG_ENDIAN
+                   && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
+                   && bitsize < GET_MODE_BITSIZE (GET_MODE (op0)))
+                 op0 = expand_shift (LSHIFT_EXPR, GET_MODE (op0), op0,
+                                     size_int (GET_MODE_BITSIZE
+                                               (GET_MODE (op0))
+                                               - bitsize),
+                                     op0, 1);
+
+               emit_move_insn (new, op0);
+               op0 = copy_rtx (new);
+               PUT_MODE (op0, BLKmode);
+             }
+         }
+       else
+         /* Get a reference to just this component.  */
+         op0 = change_address (op0, mode1,
+                               plus_constant (XEXP (op0, 0),
+                                              (bitpos / BITS_PER_UNIT)));
+
+       MEM_ALIAS_SET (op0) = get_alias_set (exp);
+
+       /* Adjust the alignment in case the bit position is not
+          a multiple of the alignment of the inner object.  */
+       while (bitpos % alignment != 0)
+         alignment >>= 1;
+
+       if (GET_CODE (XEXP (op0, 0)) == REG)
+         mark_reg_pointer (XEXP (op0, 0), alignment);
+
+       MEM_IN_STRUCT_P (op0) = 1;
+       MEM_VOLATILE_P (op0) |= volatilep;
+
+       *palign = alignment;
+       return op0;
+      }
+
+    default:
+      break;
+
+    }
+
+  return expand_expr (exp, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+}
+\f
+/* Return the tree node if a ARG corresponds to a string constant or zero
+   if it doesn't.  If we return non-zero, set *PTR_OFFSET to the offset
+   in bytes within the string that ARG is accessing.  The type of the
+   offset will be `sizetype'.  */
 
 tree
 string_constant (arg, ptr_offset)
@@ -8263,7 +8948,7 @@ string_constant (arg, ptr_offset)
   if (TREE_CODE (arg) == ADDR_EXPR
       && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST)
     {
-      *ptr_offset = integer_zero_node;
+      *ptr_offset = size_zero_node;
       return TREE_OPERAND (arg, 0);
     }
   else if (TREE_CODE (arg) == PLUS_EXPR)
@@ -8277,13 +8962,13 @@ string_constant (arg, ptr_offset)
       if (TREE_CODE (arg0) == ADDR_EXPR
          && TREE_CODE (TREE_OPERAND (arg0, 0)) == STRING_CST)
        {
-         *ptr_offset = arg1;
+         *ptr_offset = convert (sizetype, arg1);
          return TREE_OPERAND (arg0, 0);
        }
       else if (TREE_CODE (arg1) == ADDR_EXPR
               && TREE_CODE (TREE_OPERAND (arg1, 0)) == STRING_CST)
        {
-         *ptr_offset = arg0;
+         *ptr_offset = convert (sizetype, arg0);
          return TREE_OPERAND (arg1, 0);
        }
     }
@@ -8377,7 +9062,7 @@ expand_increment (exp, post, ignore)
   if (this_optab == sub_optab
       && GET_CODE (op1) == CONST_INT)
     {
-      op1 = GEN_INT (- INTVAL (op1));
+      op1 = GEN_INT (-INTVAL (op1));
       this_optab = add_optab;
     }
 
@@ -8485,7 +9170,7 @@ expand_increment (exp, post, ignore)
 
   /* Increment however we can.  */
   op1 = expand_binop (mode, this_optab, value, op1,
-                     current_function_check_memory_usage ? NULL_RTX : op0,
+                     current_function_check_memory_usage ? NULL_RTX : op0,
                      TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
   /* Make sure the value is stored into OP0.  */
   if (op1 != op0)
@@ -8504,14 +9189,14 @@ preexpand_calls (exp)
      tree exp;
 {
   register int nops, i;
-  int type = TREE_CODE_CLASS (TREE_CODE (exp));
+  int class = TREE_CODE_CLASS (TREE_CODE (exp));
 
   if (! do_preexpand_calls)
     return;
 
   /* Only expressions and references can contain calls.  */
 
-  if (type != 'e' && type != '<' && type != '1' && type != '2' && type != 'r')
+  if (! IS_EXPR_CODE_CLASS (class) && class != 'r')
     return;
 
   switch (TREE_CODE (exp))
@@ -8520,7 +9205,8 @@ preexpand_calls (exp)
       /* Do nothing if already expanded.  */
       if (CALL_EXPR_RTL (exp) != 0
          /* Do nothing if the call returns a variable-sized object.  */
-         || TREE_CODE (TYPE_SIZE (TREE_TYPE(exp))) != INTEGER_CST
+         || (TREE_CODE (TREE_TYPE (exp)) != VOID_TYPE
+             && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST)
          /* Do nothing to built-in functions.  */
          || (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
              && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
@@ -8553,12 +9239,12 @@ preexpand_calls (exp)
     case SAVE_EXPR:
       if (SAVE_EXPR_RTL (exp) != 0)
        return;
-      
+
     default:
       break;
     }
 
-  nops = tree_code_length[(int) TREE_CODE (exp)];
+  nops = TREE_CODE_LENGTH (TREE_CODE (exp));
   for (i = 0; i < nops; i++)
     if (TREE_OPERAND (exp, i) != 0)
       {
@@ -8568,9 +9254,8 @@ preexpand_calls (exp)
          ;
        else
          {
-           type = TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, i)));
-           if (type == 'e' || type == '<' || type == '1' || type == '2'
-               || type == 'r')
+           class = TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, i)));
+           if (IS_EXPR_CODE_CLASS (class) || class == 'r')
              preexpand_calls (TREE_OPERAND (exp, i));
          }
       }
@@ -8600,7 +9285,10 @@ clear_pending_stack_adjust ()
       && EXIT_IGNORE_STACK
       && ! (DECL_INLINE (current_function_decl) && ! flag_no_inline)
       && ! flag_inline_functions)
-    pending_stack_adjust = 0;
+    {
+      stack_pointer_delta -= pending_stack_adjust,
+      pending_stack_adjust = 0;
+    }
 #endif
 }
 
@@ -8715,6 +9403,15 @@ do_jump (exp, if_false_label, if_true_label)
       do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
       break;
 
+    case WITH_RECORD_EXPR:
+      /* Put the object on the placeholder list, recurse through our first
+        operand, and pop the list.  */
+      placeholder_list = tree_cons (TREE_OPERAND (exp, 1), NULL_TREE,
+                                   placeholder_list);
+      do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
+      placeholder_list = TREE_CHAIN (placeholder_list);
+      break;
+
 #if 0
       /* This is never less insns than evaluating the PLUS_EXPR followed by
         a test and can be longer if the test is eliminated.  */
@@ -8746,7 +9443,7 @@ do_jump (exp, if_false_label, if_true_label)
       if (! SLOW_BYTE_ACCESS
          && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
          && TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_WIDE_INT
-         && (i = floor_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))) >= 0
+         && (i = tree_floor_log2 (TREE_OPERAND (exp, 1))) >= 0
          && (mode = mode_for_size (i + 1, MODE_INT, 0)) != BLKmode
          && (type = type_for_mode (mode, 1)) != 0
          && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
@@ -8795,18 +9492,18 @@ do_jump (exp, if_false_label, if_true_label)
     case BIT_FIELD_REF:
     case ARRAY_REF:
       {
-       int bitsize, bitpos, unsignedp;
+       HOST_WIDE_INT bitsize, bitpos;
+       int unsignedp;
        enum machine_mode mode;
        tree type;
        tree offset;
        int volatilep = 0;
-       int alignment;
+       unsigned int alignment;
 
        /* Get description of this reference.  We don't actually care
           about the underlying object here.  */
-       get_inner_reference (exp, &bitsize, &bitpos, &offset,
-                            &mode, &unsignedp, &volatilep,
-                            &alignment);
+       get_inner_reference (exp, &bitsize, &bitpos, &offset, &mode,
+                            &unsignedp, &volatilep, &alignment);
 
        type = type_for_size (bitsize, unsignedp);
        if (! SLOW_BYTE_ACCESS
@@ -8888,7 +9585,7 @@ do_jump (exp, if_false_label, if_true_label)
          do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
 
        else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
-                && !can_compare_p (TYPE_MODE (inner_type)))
+                && !can_compare_p (EQ, TYPE_MODE (inner_type), ccp_jump))
          do_jump_by_parts_equality (exp, if_false_label, if_true_label);
        else
          do_compare_and_jump (exp, EQ, EQ, if_false_label, if_true_label);
@@ -8928,7 +9625,7 @@ do_jump (exp, if_false_label, if_true_label)
          do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
 
        else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
-                && !can_compare_p (TYPE_MODE (inner_type)))
+                && !can_compare_p (NE, TYPE_MODE (inner_type), ccp_jump))
          do_jump_by_parts_equality (exp, if_true_label, if_false_label);
        else
          do_compare_and_jump (exp, NE, NE, if_false_label, if_true_label);
@@ -8936,41 +9633,114 @@ do_jump (exp, if_false_label, if_true_label)
       }
 
     case LT_EXPR:
-      if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
-          == MODE_INT)
-         && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
+      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+      if (GET_MODE_CLASS (mode) == MODE_INT
+         && ! can_compare_p (LT, mode, ccp_jump))
        do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label);
       else
        do_compare_and_jump (exp, LT, LTU, if_false_label, if_true_label);
       break;
 
     case LE_EXPR:
-      if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
-          == MODE_INT)
-         && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
+      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+      if (GET_MODE_CLASS (mode) == MODE_INT
+         && ! can_compare_p (LE, mode, ccp_jump))
        do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label);
       else
        do_compare_and_jump (exp, LE, LEU, if_false_label, if_true_label);
       break;
 
     case GT_EXPR:
-      if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
-          == MODE_INT)
-         && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
+      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+      if (GET_MODE_CLASS (mode) == MODE_INT
+         && ! can_compare_p (GT, mode, ccp_jump))
        do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label);
       else
        do_compare_and_jump (exp, GT, GTU, if_false_label, if_true_label);
       break;
 
     case GE_EXPR:
-      if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
-          == MODE_INT)
-         && !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
+      mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+      if (GET_MODE_CLASS (mode) == MODE_INT
+         && ! can_compare_p (GE, mode, ccp_jump))
        do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label);
       else
        do_compare_and_jump (exp, GE, GEU, if_false_label, if_true_label);
       break;
 
+    case UNORDERED_EXPR:
+    case ORDERED_EXPR:
+      {
+       enum rtx_code cmp, rcmp;
+       int do_rev;
+
+       if (code == UNORDERED_EXPR)
+         cmp = UNORDERED, rcmp = ORDERED;
+       else
+         cmp = ORDERED, rcmp = UNORDERED;
+       mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+       do_rev = 0;
+       if (! can_compare_p (cmp, mode, ccp_jump)
+           && (can_compare_p (rcmp, mode, ccp_jump)
+               /* If the target doesn't provide either UNORDERED or ORDERED
+                  comparisons, canonicalize on UNORDERED for the library.  */
+               || rcmp == UNORDERED))
+         do_rev = 1;
+
+        if (! do_rev)
+         do_compare_and_jump (exp, cmp, cmp, if_false_label, if_true_label);
+       else
+         do_compare_and_jump (exp, rcmp, rcmp, if_true_label, if_false_label);
+      }
+      break;
+
+    {
+      enum rtx_code rcode1;
+      enum tree_code tcode2;
+
+      case UNLT_EXPR:
+       rcode1 = UNLT;
+       tcode2 = LT_EXPR;
+       goto unordered_bcc;
+      case UNLE_EXPR:
+       rcode1 = UNLE;
+       tcode2 = LE_EXPR;
+       goto unordered_bcc;
+      case UNGT_EXPR:
+       rcode1 = UNGT;
+       tcode2 = GT_EXPR;
+       goto unordered_bcc;
+      case UNGE_EXPR:
+       rcode1 = UNGE;
+       tcode2 = GE_EXPR;
+       goto unordered_bcc;
+      case UNEQ_EXPR:
+       rcode1 = UNEQ;
+       tcode2 = EQ_EXPR;
+       goto unordered_bcc;
+
+      unordered_bcc:
+        mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+       if (can_compare_p (rcode1, mode, ccp_jump))
+         do_compare_and_jump (exp, rcode1, rcode1, if_false_label,
+                              if_true_label);
+       else
+         {
+           tree op0 = save_expr (TREE_OPERAND (exp, 0));
+           tree op1 = save_expr (TREE_OPERAND (exp, 1));
+           tree cmp0, cmp1;
+
+           /* If the target doesn't support combined unordered
+              compares, decompose into UNORDERED + comparison.  */
+           cmp0 = fold (build (UNORDERED_EXPR, TREE_TYPE (exp), op0, op1));
+           cmp1 = fold (build (tcode2, TREE_TYPE (exp), op0, op1));
+           exp = build (TRUTH_ORIF_EXPR, TREE_TYPE (exp), cmp0, cmp1);
+           do_jump (exp, if_false_label, if_true_label);
+         }
+      }
+      break;
+
     default:
     normal:
       temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
@@ -8994,7 +9764,7 @@ do_jump (exp, if_false_label, if_true_label)
            emit_jump (target);
        }
       else if (GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
-              && ! can_compare_p (GET_MODE (temp)))
+              && ! can_compare_p (NE, GET_MODE (temp), ccp_jump))
        /* Note swapping the labels gives us not-equal.  */
        do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label);
       else if (GET_MODE (temp) != VOIDmode)
@@ -9191,7 +9961,7 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
      int unsignedp;
      enum machine_mode mode;
      rtx size;
-     int align;
+     unsigned int align;
 {
   rtx tem;
 
@@ -9240,7 +10010,7 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
       unsignedp = 1;
     }
 #endif
-       
+
   emit_cmp_insn (op0, op1, code, size, mode, unsignedp, align);
 
   return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
@@ -9263,7 +10033,7 @@ do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, size, align,
      int unsignedp;
      enum machine_mode mode;
      rtx size;
-     int align;
+     unsigned int align;
      rtx if_false_label, if_true_label;
 {
   rtx tem;
@@ -9368,6 +10138,7 @@ do_compare_and_jump (exp, signed_code, unsigned_code, if_false_label,
      enum rtx_code signed_code, unsigned_code;
      rtx if_false_label, if_true_label;
 {
+  unsigned int align0, align1;
   register rtx op0, op1;
   register tree type;
   register enum machine_mode mode;
@@ -9375,11 +10146,11 @@ do_compare_and_jump (exp, signed_code, unsigned_code, if_false_label,
   enum rtx_code code;
 
   /* Don't crash if the comparison was erroneous.  */
-  op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+  op0 = expand_expr_unaligned (TREE_OPERAND (exp, 0), &align0);
   if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK)
     return;
 
-  op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
+  op1 = expand_expr_unaligned (TREE_OPERAND (exp, 1), &align1);
   type = TREE_TYPE (TREE_OPERAND (exp, 0));
   mode = TYPE_MODE (type);
   unsignedp = TREE_UNSIGNED (type);
@@ -9417,7 +10188,7 @@ do_compare_and_jump (exp, signed_code, unsigned_code, if_false_label,
   do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode,
                           ((mode == BLKmode)
                            ? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX),
-                          TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT,
+                          MIN (align0, align1),
                           if_false_label, if_true_label);
 }
 \f
@@ -9533,6 +10304,29 @@ do_store_flag (exp, target, mode, only_cheap)
       else
        code = unsignedp ? GEU : GE;
       break;
+
+    case UNORDERED_EXPR:
+      code = UNORDERED;
+      break;
+    case ORDERED_EXPR:
+      code = ORDERED;
+      break;
+    case UNLT_EXPR:
+      code = UNLT;
+      break;
+    case UNLE_EXPR:
+      code = UNLE;
+      break;
+    case UNGT_EXPR:
+      code = UNGT;
+      break;
+    case UNGE_EXPR:
+      code = UNGE;
+      break;
+    case UNEQ_EXPR:
+      code = UNEQ;
+      break;
+
     default:
       abort ();
     }
@@ -9564,8 +10358,9 @@ do_store_flag (exp, target, mode, only_cheap)
       if (TREE_CODE (inner) == RSHIFT_EXPR
          && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST
          && TREE_INT_CST_HIGH (TREE_OPERAND (inner, 1)) == 0
-         && (bitnum + TREE_INT_CST_LOW (TREE_OPERAND (inner, 1))
-             < TYPE_PRECISION (type)))
+         && bitnum < TYPE_PRECISION (type)
+         && 0 > compare_tree_int (TREE_OPERAND (inner, 1),
+                                  bitnum - TYPE_PRECISION (type)))
        {
          bitnum += TREE_INT_CST_LOW (TREE_OPERAND (inner, 1));
          inner = TREE_OPERAND (inner, 0);
@@ -9582,7 +10377,7 @@ do_store_flag (exp, target, mode, only_cheap)
 #endif
                       );
 
-      if (subtarget == 0 || GET_CODE (subtarget) != REG
+      if (! get_subtarget (subtarget)
          || GET_MODE (subtarget) != operand_mode
          || ! safe_from_p (subtarget, inner, 1))
        subtarget = 0;
@@ -9608,8 +10403,9 @@ do_store_flag (exp, target, mode, only_cheap)
     }
 
   /* Now see if we are likely to be able to do this.  Return if not.  */
-  if (! can_compare_p (operand_mode))
+  if (! can_compare_p (code, operand_mode, ccp_store_flag))
     return 0;
+
   icode = setcc_gen_code[(int) code];
   if (icode == CODE_FOR_nothing
       || (only_cheap && insn_data[(int) icode].operand[0].mode != mode))
@@ -9630,9 +10426,9 @@ do_store_flag (exp, target, mode, only_cheap)
       else
        return 0;
     }
-      
+
   preexpand_calls (exp);
-  if (subtarget == 0 || GET_CODE (subtarget) != REG
+  if (! get_subtarget (target)
       || GET_MODE (subtarget) != operand_mode
       || ! safe_from_p (subtarget, arg1, 1))
     subtarget = 0;
@@ -9759,4 +10555,4 @@ do_tablejump (index, mode, range, table_label, default_label)
     emit_barrier ();
 }
 
-#endif /* HAVE_tablejump */
+#endif /* HAVE_tablejump  */