OSDN Git Service

* function.c (free_temps_for_rtl_expr): Don't free slots
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index c4d0f14..fb266e2 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.
 
@@ -41,8 +42,7 @@ Boston, MA 02111-1307, USA.  */
 #include "defaults.h"
 #include "toplev.h"
 #include "ggc.h"
-
-#define CEIL(x,y) (((x) + (y) - 1) / (y))
+#include "tm_p.h"
 
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
@@ -89,6 +89,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
@@ -127,37 +130,39 @@ struct clear_by_pieces
 
 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 int move_by_pieces_ninsns PARAMS ((unsigned 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, int, unsigned int));
+static void clear_by_pieces_1  PARAMS ((rtx (*) (rtx, ...),
+                                        enum machine_mode,
+                                        struct clear_by_pieces *));
+static int is_zeros_p          PARAMS ((tree));
+static int mostly_zeros_p      PARAMS ((tree));
+static void store_constructor_field PARAMS ((rtx, int, int, enum machine_mode,
+                                            tree, tree, unsigned int, int));
+static void store_constructor  PARAMS ((tree, rtx, unsigned int, int, int));
+static rtx store_field         PARAMS ((rtx, int, int, enum machine_mode,
+                                        tree, enum machine_mode, int,
+                                        unsigned int, 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 safe_from_p         PARAMS ((rtx, tree, int));
+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
@@ -194,7 +199,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,17 +284,37 @@ 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;
+  arg_space_so_far = 0;
   inhibit_defer_pop = 0;
   saveregs_value = 0;
   apply_args_value = 0;
   forced_labels = 0;
 }
 
+void
+mark_expr_status (p)
+     struct expr_status *p;
+{
+  if (p == NULL)
+    return;
+
+  ggc_mark_rtx (p->x_saveregs_value);
+  ggc_mark_rtx (p->x_apply_args_value);
+  ggc_mark_rtx (p->x_forced_labels);
+}
+
+void
+free_expr_status (f)
+     struct function *f;
+{
+  free (f->expr);
+  f->expr = NULL;
+}
+
 /* Small sanity check that the queue is empty at the end of a function.  */
 void
 finish_expr_for_function ()
@@ -1337,7 +1362,8 @@ convert_modes (mode, oldmode, x, unsignedp)
 void
 move_by_pieces (to, from, len, align)
      rtx to, from;
-     int len, align;
+     int len;
+     unsigned int align;
 {
   struct move_by_pieces data;
   rtx to_addr = XEXP (to, 0), from_addr = XEXP (from, 0);
@@ -1412,7 +1438,7 @@ move_by_pieces (to, from, len, align)
        data.to_addr = copy_addr_to_reg (to_addr);
     }
 
-  if (! SLOW_UNALIGNED_ACCESS
+  if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
       || align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
     align = MOVE_MAX;
 
@@ -1432,7 +1458,7 @@ move_by_pieces (to, from, len, align)
       icode = mov_optab->handlers[(int) mode].insn_code;
       if (icode != CODE_FOR_nothing
          && align >= MIN (BIGGEST_ALIGNMENT / BITS_PER_UNIT,
-                          GET_MODE_SIZE (mode)))
+                          (unsigned int) GET_MODE_SIZE (mode)))
        move_by_pieces_1 (GEN_FCN (icode), mode, &data);
 
       max_size = GET_MODE_SIZE (mode);
@@ -1449,12 +1475,12 @@ move_by_pieces (to, from, len, align)
 static int
 move_by_pieces_ninsns (l, align)
      unsigned int l;
-     int align;
+     unsigned int align;
 {
   register int n_insns = 0;
   int max_size = MOVE_MAX + 1;
 
-  if (! SLOW_UNALIGNED_ACCESS
+  if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
       || align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
     align = MOVE_MAX;
 
@@ -1473,8 +1499,7 @@ move_by_pieces_ninsns (l, align)
 
       icode = mov_optab->handlers[(int) mode].insn_code;
       if (icode != CODE_FOR_nothing
-         && align >= MIN (BIGGEST_ALIGNMENT / BITS_PER_UNIT,
-                          GET_MODE_SIZE (mode)))
+         && align >= GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT)
        n_insns += l / GET_MODE_SIZE (mode), l %= GET_MODE_SIZE (mode);
 
       max_size = GET_MODE_SIZE (mode);
@@ -1489,7 +1514,7 @@ 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;
 {
@@ -1551,7 +1576,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
@@ -1860,7 +1885,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;
@@ -1882,7 +1908,10 @@ emit_group_load (dst, orig_src, ssize, align)
   src = orig_src;
   if (GET_CODE (src) != MEM)
     {
-      src = gen_reg_rtx (GET_MODE (orig_src));
+      if (GET_CODE (src) == VOIDmode)
+       src = gen_reg_rtx (GET_MODE (dst));
+      else
+       src = gen_reg_rtx (GET_MODE (orig_src));
       emit_move_insn (src, orig_src);
     }
 
@@ -1900,13 +1929,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 * BITS_PER_UNIT >= GET_MODE_ALIGNMENT (mode)
+         && bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
          && bytelen == GET_MODE_SIZE (mode))
        {
          tmps[i] = gen_reg_rtx (mode);
@@ -1953,7 +1982,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;
@@ -2037,21 +2067,18 @@ 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 * BITS_PER_UNIT >= 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();
 
   /* Copy from the pseudo into the (probable) hard reg.  */
@@ -2066,18 +2093,17 @@ 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 bitsize = MIN (TYPE_ALIGN (type), BITS_PER_WORD);
       int bitpos, xbitpos, big_endian_correction = 0;
       
       if (tgtblk == 0)
@@ -2206,7 +2232,8 @@ use_group_regs (call_fusage, regs)
 static void
 clear_by_pieces (to, len, align)
      rtx to;
-     int len, align;
+     int len;
+     unsigned int align;
 {
   struct clear_by_pieces data;
   rtx to_addr = XEXP (to, 0);
@@ -2257,7 +2284,7 @@ clear_by_pieces (to, len, align)
        data.to_addr = copy_addr_to_reg (to_addr);
     }
 
-  if (! SLOW_UNALIGNED_ACCESS
+  if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
       || align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
     align = MOVE_MAX;
 
@@ -2276,8 +2303,7 @@ clear_by_pieces (to, len, align)
 
       icode = mov_optab->handlers[(int) mode].insn_code;
       if (icode != CODE_FOR_nothing
-         && align >= MIN (BIGGEST_ALIGNMENT / BITS_PER_UNIT,
-                          GET_MODE_SIZE (mode)))
+         && align >= GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT)
        clear_by_pieces_1 (GEN_FCN (icode), mode, &data);
 
       max_size = GET_MODE_SIZE (mode);
@@ -2294,7 +2320,7 @@ 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;
 {
@@ -2335,7 +2361,7 @@ rtx
 clear_storage (object, size, align)
      rtx object;
      rtx size;
-     int align;
+     unsigned int align;
 {
 #ifdef TARGET_MEM_FUNCTIONS
   static tree fn;
@@ -2609,19 +2635,78 @@ emit_move_insn_1 (x, y)
        }
       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 = "function uses short complex types";
+
+                     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 ();
@@ -2633,6 +2718,8 @@ emit_move_insn_1 (x, y)
   else if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
     {
       rtx last_insn = 0;
+      rtx seq;
+      int need_clobber;
       
 #ifdef PUSH_ROUNDING
 
@@ -2645,15 +2732,9 @@ emit_move_insn_1 (x, y)
        }
 #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))
-       {
-         emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
-       }
+      start_sequence ();
 
+      need_clobber = 0;
       for (i = 0;
           i < (GET_MODE_SIZE (mode)  + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
           i++)
@@ -2675,9 +2756,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
@@ -2800,18 +2899,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
@@ -2871,7 +2972,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
          /* 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)
+         && ((! SLOW_UNALIGNED_ACCESS (word_mode, align))
              || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT
              || PUSH_ROUNDING (align) == align)
          && PUSH_ROUNDING (INTVAL (size)) == INTVAL (size))
@@ -2965,7 +3066,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
 
          /* 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);
@@ -3106,7 +3207,7 @@ 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
     {
@@ -3178,6 +3279,9 @@ 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)
+    anti_adjust_stack (alignment_pad);
 }
 \f
 /* Expand an assignment that stores the value of FROM into TO.
@@ -3224,7 +3328,7 @@ expand_assignment (to, from, want_value, suggest_reg)
       int unsignedp;
       int volatilep = 0;
       tree tem;
-      int alignment;
+      unsigned int alignment;
 
       push_temp_slots ();
       tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
@@ -3417,13 +3521,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)) / BITS_PER_UNIT);
+      else
+       emit_move_insn (to_rtx, temp);
+
       preserve_temp_slots (to_rtx);
       free_temp_slots ();
       pop_temp_slots ();
@@ -3754,8 +3865,7 @@ store_expr (exp, target, want_value)
              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)));
              rtx copy_size_rtx = expand_expr (copy_size, NULL_RTX,
                                               VOIDmode, 0);
              rtx label = 0;
@@ -3942,7 +4052,7 @@ store_constructor_field (target, bitsize, bitpos,
      int bitsize, bitpos;
      enum machine_mode mode;
      tree exp, type;
-     int align;
+     unsigned int align;
      int cleared;
 {
   if (TREE_CODE (exp) == CONSTRUCTOR
@@ -3953,28 +4063,37 @@ 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));
+      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);
+                int_size_in_bytes (type), 0);
 }
 
 /* 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.  */
+   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;
+     int size;
 {
   tree type = TREE_TYPE (exp);
 #ifdef WORD_REGISTER_OPERATIONS
@@ -3989,7 +4108,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;
     }
@@ -4001,9 +4120,17 @@ 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) / BITS_PER_UNIT);
+       }
 
       /* If we are building a static constructor into a register,
         set the initial value as zero so we can fold the value into
@@ -4021,17 +4148,18 @@ 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))
+      else if (size > 0
+              && ((list_length (CONSTRUCTOR_ELTS (exp))
+                   != list_length (TYPE_FIELDS (type)))
+                  || mostly_zeros_p (exp)))
        {
          if (! cleared)
-           clear_storage (target, expr_size (exp),
+           clear_storage (target, GEN_INT (size),
                           (align + BITS_PER_UNIT - 1) / BITS_PER_UNIT);
 
          cleared = 1;
        }
-      else
+      else if (! cleared)
        /* Inform later passes that the old value is dead.  */
        emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
 
@@ -4060,7 +4188,11 @@ store_constructor (exp, target, align, cleared)
          if (cleared && is_zeros_p (TREE_VALUE (elt)))
            continue;
 
-         bitsize = TREE_INT_CST_LOW (DECL_SIZE (field));
+         if (TREE_CODE (DECL_SIZE (field)) == INTEGER_CST)
+           bitsize = TREE_INT_CST_LOW (DECL_SIZE (field));
+         else
+           bitsize = -1;
+
          unsignedp = TREE_UNSIGNED (field);
          mode = DECL_MODE (field);
          if (DECL_BIT_FIELD (field))
@@ -4083,11 +4215,12 @@ store_constructor (exp, target, align, cleared)
              rtx offset_rtx;
 
              if (contains_placeholder_p (offset))
-               offset = build (WITH_RECORD_EXPR, sizetype,
+               offset = build (WITH_RECORD_EXPR, bitsizetype,
                                offset, make_tree (TREE_TYPE (exp), target));
 
-             offset = size_binop (FLOOR_DIV_EXPR, offset,
-                                  size_int (BITS_PER_UNIT));
+             offset = size_binop (EXACT_DIV_EXPR, offset,
+                                  bitsize_int (BITS_PER_UNIT));
+             offset = convert (sizetype, offset);
 
              offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
              if (GET_CODE (to_rtx) != MEM)
@@ -4205,10 +4338,10 @@ store_constructor (exp, target, align, cleared)
              || 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),
+           clear_storage (target, GEN_INT (size),
                           (align + BITS_PER_UNIT - 1) / BITS_PER_UNIT);
          cleared = 1;
        }
@@ -4228,16 +4361,25 @@ store_constructor (exp, target, align, cleared)
          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)
+           {
+             if (TREE_CODE (TYPE_SIZE (elttype)) == INTEGER_CST
+                 && TREE_INT_CST_HIGH (TYPE_SIZE (elttype)) == 0)
+               bitsize = TREE_INT_CST_LOW (TYPE_SIZE (elttype));
+             else
+               bitsize = -1;
+           }
+         else
+           bitsize = GET_MODE_BITSIZE (mode);
 
          if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
            {
@@ -4294,17 +4436,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);
 
@@ -4317,11 +4462,6 @@ 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)
@@ -4331,14 +4471,15 @@ store_constructor (exp, target, align, cleared)
              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);
@@ -4375,10 +4516,10 @@ store_constructor (exp, target, align, cleared)
         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),
+           clear_storage (target, GEN_INT (size),
                           TYPE_ALIGN (type) / BITS_PER_UNIT);
          return;
        }
@@ -4386,8 +4527,8 @@ store_constructor (exp, target, align, cleared)
       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 ();
@@ -4568,7 +4709,7 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
      tree exp;
      enum machine_mode value_mode;
      int unsignedp;
-     int align;
+     unsigned int align;
      int total_size;
      int alias_set;
 {
@@ -4627,9 +4768,19 @@ 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 * BITS_PER_UNIT < GET_MODE_ALIGNMENT (mode)
+             || bitpos % GET_MODE_ALIGNMENT (mode)))
+      || (mode == BLKmode && SLOW_UNALIGNED_ACCESS (mode, align)
+         && (TYPE_ALIGN (TREE_TYPE (exp)) > align * BITS_PER_UNIT
+             || 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)
+         && (TREE_INT_CST_HIGH (TYPE_SIZE (TREE_TYPE (exp))) != 0
+             || TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp))) != bitsize)))
     {
       rtx temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
 
@@ -4656,6 +4807,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) / BITS_PER_UNIT;
+
          if (GET_CODE (target) != MEM || GET_CODE (temp) != MEM
              || bitpos % BITS_PER_UNIT != 0)
            abort ();
@@ -4664,10 +4817,17 @@ 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 * BITS_PER_UNIT)) != 0)
+           align >>= 1;
+
          emit_block_move (target, temp,
                           GEN_INT ((bitsize + BITS_PER_UNIT - 1)
                                    / BITS_PER_UNIT),
-                          1);
+                          align);
 
          return value_mode == VOIDmode ? const0_rtx : target;
        }
@@ -4764,12 +4924,12 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
      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;
   unsigned int alignment = BIGGEST_ALIGNMENT;
 
   if (TREE_CODE (exp) == COMPONENT_REF)
@@ -4814,7 +4974,7 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
          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 constant = bitsize_int (0), var = pos;
 
          /* If this field hasn't been filled in yet, don't go
             past it.  This should only happen when folding expressions
@@ -4828,12 +4988,14 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
              && 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;
+           constant = pos, var = bitsize_int (0);
 
          *pbitpos += TREE_INT_CST_LOW (constant);
-         offset = size_binop (PLUS_EXPR, offset,
-                              size_binop (EXACT_DIV_EXPR, var,
-                                          size_int (BITS_PER_UNIT)));
+         offset
+           = size_binop (PLUS_EXPR, offset,
+                         convert (sizetype,
+                                  size_binop (EXACT_DIV_EXPR, var,
+                                              bitsize_int (BITS_PER_UNIT))));
        }
 
       else if (TREE_CODE (exp) == ARRAY_REF)
@@ -4890,22 +5052,21 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
                 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)))));
+             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);
+               xindex = build (WITH_RECORD_EXPR, ssizetype, xindex, exp);
 
-             offset = size_binop (PLUS_EXPR, offset, xindex);
+             offset
+               = size_binop (PLUS_EXPR, offset, convert (sizetype, xindex));
            }
        }
       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;
@@ -5444,6 +5605,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.
    In the case of a void EXP, const0_rtx is returned.
@@ -5486,9 +5667,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);
@@ -5547,10 +5725,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)
@@ -5558,11 +5738,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);
@@ -5574,7 +5755,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;
     }
 
@@ -5694,7 +5882,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)))
@@ -6084,7 +6272,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
@@ -6186,7 +6374,8 @@ 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;
        }
 
@@ -6212,7 +6401,7 @@ expand_expr (exp, target, tmode, modifier)
        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;
@@ -6252,6 +6441,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;
       }
 
@@ -6263,8 +6460,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.
@@ -6273,14 +6469,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 &.
@@ -6381,7 +6573,8 @@ expand_expr (exp, 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))))
                      {
@@ -6413,7 +6606,7 @@ expand_expr (exp, target, tmode, modifier)
        int bitpos;
        tree offset;
        int volatilep = 0;
-       int alignment;
+       unsigned int alignment;
        tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
                                        &mode1, &unsignedp, &volatilep,
                                        &alignment);
@@ -6434,15 +6627,17 @@ expand_expr (exp, target, tmode, modifier)
                                != 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));
@@ -6452,6 +6647,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 ();
 
@@ -6464,12 +6673,12 @@ 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
+               && bitsize != 0
                && (bitpos % bitsize) == 0 
                && (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
                && (alignment * BITS_PER_UNIT) == GET_MODE_ALIGNMENT (mode1))
@@ -6543,13 +6752,34 @@ 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))
+                            < (unsigned int) 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)
+                        && ((TREE_INT_CST_HIGH (TYPE_SIZE (TREE_TYPE (exp)))
+                             != 0)
+                            || (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp)))
+                                != bitsize))))))
+           || (modifier != EXPAND_CONST_ADDRESS
+               && modifier != EXPAND_INITIALIZER
+               && mode == BLKmode
+               && SLOW_UNALIGNED_ACCESS (mode, alignment)
+               && (TYPE_ALIGN (type) > alignment * BITS_PER_UNIT
+                   || 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)
@@ -6627,7 +6857,7 @@ expand_expr (exp, target, tmode, modifier)
 
        if (GET_CODE (op0) == MEM)
          MEM_ALIAS_SET (op0) = get_alias_set (exp);
-
        if (GET_CODE (XEXP (op0, 0)) == REG)
          mark_reg_pointer (XEXP (op0, 0), alignment);
 
@@ -6773,7 +7003,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;
 
@@ -6808,6 +7038,16 @@ expand_expr (exp, target, tmode, modifier)
       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)
@@ -6823,11 +7063,13 @@ 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, 1, int_size_in_bytes (type), 0);
          else
            abort ();
 
@@ -7058,21 +7300,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);
@@ -7318,7 +7550,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),
@@ -7399,6 +7632,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)
@@ -7775,6 +8015,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)
@@ -7844,7 +8089,6 @@ 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);
@@ -8165,7 +8409,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;
 
@@ -8230,8 +8474,318 @@ 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))
+         {
+           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_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);
+
+               i = TREE_INT_CST_LOW (index);
+               if (TREE_CODE (init) == CONSTRUCTOR)
+                 {
+                   tree elem = CONSTRUCTOR_ELTS (init);
+
+                   while (elem
+                          && !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;
+       int bitsize;
+       int 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.  */
+           if (size > BITS_PER_UNIT)
+             emit_library_call (chkr_check_addr_libfunc, 1, 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 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 * BITS_PER_UNIT
+                   || 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)
@@ -8243,7 +8797,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)
@@ -8257,13 +8811,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);
        }
     }
@@ -8542,10 +9096,17 @@ preexpand_calls (exp)
   for (i = 0; i < nops; i++)
     if (TREE_OPERAND (exp, i) != 0)
       {
-       type = TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, i)));
-       if (type == 'e' || type == '<' || type == '1' || type == '2'
-           || type == 'r')
-         preexpand_calls (TREE_OPERAND (exp, i));
+       if (TREE_CODE (exp) == TARGET_EXPR && i == 2)
+         /* We don't need to preexpand the cleanup for a TARGET_EXPR.
+            It doesn't happen before the call is made.  */
+         ;
+       else
+         {
+           type = TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, i)));
+           if (type == 'e' || type == '<' || type == '1' || type == '2'
+               || type == 'r')
+             preexpand_calls (TREE_OPERAND (exp, i));
+         }
       }
 }
 \f
@@ -8688,6 +9249,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.  */
@@ -8773,7 +9343,7 @@ do_jump (exp, if_false_label, if_true_label)
        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.  */
@@ -8861,7 +9431,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);
@@ -8901,7 +9471,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);
@@ -8909,41 +9479,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);
@@ -8967,7 +9610,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)
@@ -9164,7 +9807,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;
 
@@ -9236,7 +9879,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;
@@ -9341,6 +9984,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;
@@ -9348,11 +9992,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);
@@ -9390,7 +10034,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) / BITS_PER_UNIT,
                           if_false_label, if_true_label);
 }
 \f
@@ -9506,6 +10150,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 ();
     }
@@ -9581,8 +10248,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))