OSDN Git Service

* pa.h (ASM_OUTPUT_SECTION_NAME): Fix typo.
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index 639d9fe..b3ca539 100644 (file)
@@ -1,5 +1,5 @@
 /* Convert tree expression to rtl instructions, for GNU compiler.
-   Copyright (C) 1988, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1988, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -27,6 +27,7 @@ Boston, MA 02111-1307, USA.  */
 #include "flags.h"
 #include "regs.h"
 #include "hard-reg-set.h"
+#include "except.h"
 #include "function.h"
 #include "insn-flags.h"
 #include "insn-codes.h"
@@ -93,10 +94,6 @@ int pending_stack_adjust;
    and in other cases as well.  */
 int inhibit_defer_pop;
 
-/* A list of all cleanups which belong to the arguments of
-   function calls being expanded by expand_call.  */
-tree cleanups_this_call;
-
 /* When temporaries are created by TARGET_EXPRs, they are created at
    this level of temp_slot_level, so that they can remain allocated
    until no longer needed.  CLEANUP_POINT_EXPRs define the lifetime
@@ -176,6 +173,7 @@ static tree save_noncopied_parts PROTO((tree, tree));
 static tree init_noncopied_parts PROTO((tree, tree));
 static int safe_from_p         PROTO((rtx, tree));
 static int fixed_type_p                PROTO((tree));
+static rtx var_rtx             PROTO((tree));
 static int get_pointer_alignment PROTO((tree, unsigned));
 static tree string_constant    PROTO((tree, tree *));
 static tree c_strlen           PROTO((tree));
@@ -187,9 +185,8 @@ static rtx result_vector    PROTO((int, rtx));
 static rtx expand_builtin_apply_args PROTO((void));
 static rtx expand_builtin_apply        PROTO((rtx, rtx, rtx));
 static void expand_builtin_return PROTO((rtx));
-static rtx expand_increment    PROTO((tree, int));
-rtx bc_expand_increment                PROTO((struct increment_operator *, tree));
-tree bc_runtime_type_code      PROTO((tree));
+static rtx expand_increment    PROTO((tree, int, int));
+void bc_expand_increment       PROTO((struct increment_operator *, tree));
 rtx bc_allocate_local          PROTO((int, int));
 void bc_store_memory           PROTO((tree, tree));
 tree bc_expand_component_address PROTO((tree));
@@ -210,8 +207,6 @@ static void do_jump_by_parts_equality_rtx PROTO((rtx, rtx, rtx));
 static void do_jump_for_compare        PROTO((rtx, rtx, rtx));
 static rtx compare             PROTO((tree, enum rtx_code, enum rtx_code));
 static rtx do_store_flag       PROTO((tree, rtx, enum machine_mode, int));
-static tree defer_cleanups_to  PROTO((tree));
-extern void (*interim_eh_hook) PROTO((tree));
 extern tree truthvalue_conversion       PROTO((tree));
 
 /* Record for each mode whether we can move a register directly to or
@@ -240,7 +235,7 @@ enum insn_code movstr_optab[NUM_MACHINE_MODES];
 /* This array records the insn_code of insns to perform block clears.  */
 enum insn_code clrstr_optab[NUM_MACHINE_MODES];
 
-/* SLOW_UNALIGNED_ACCESS is non-zero if unaligned accesses are very slow. */
+/* SLOW_UNALIGNED_ACCESS is non-zero if unaligned accesses are very slow.  */
 
 #ifndef SLOW_UNALIGNED_ACCESS
 #define SLOW_UNALIGNED_ACCESS STRICT_ALIGNMENT
@@ -254,22 +249,23 @@ enum insn_code clrstr_optab[NUM_MACHINE_MODES];
 #define OUTGOING_REGNO(IN) (IN)
 #endif
 \f
-/* Maps used to convert modes to const, load, and store bytecodes. */
+/* Maps used to convert modes to const, load, and store bytecodes.  */
 enum bytecode_opcode mode_to_const_map[MAX_MACHINE_MODE];
 enum bytecode_opcode mode_to_load_map[MAX_MACHINE_MODE];
 enum bytecode_opcode mode_to_store_map[MAX_MACHINE_MODE];
 
 /* Initialize maps used to convert modes to const, load, and store
-   bytecodes. */
+   bytecodes.  */
+
 void
 bc_init_mode_to_opcode_maps ()
 {
   int mode;
 
   for (mode = 0; mode < (int) MAX_MACHINE_MODE; mode++)
-    mode_to_const_map[mode] =
-      mode_to_load_map[mode] =
-       mode_to_store_map[mode] = neverneverland;
+    mode_to_const_map[mode]
+      = mode_to_load_map[mode]
+      = mode_to_store_map[mode] = neverneverland;
       
 #define DEF_MODEMAP(SYM, CODE, UCODE, CONST, LOAD, STORE) \
   mode_to_const_map[(int) SYM] = CONST; \
@@ -356,7 +352,6 @@ init_expr ()
 
   pending_stack_adjust = 0;
   inhibit_defer_pop = 0;
-  cleanups_this_call = 0;
   saveregs_value = 0;
   apply_args_value = 0;
   forced_labels = 0;
@@ -374,14 +369,12 @@ save_expr_status (p)
 
   p->pending_stack_adjust = pending_stack_adjust;
   p->inhibit_defer_pop = inhibit_defer_pop;
-  p->cleanups_this_call = cleanups_this_call;
   p->saveregs_value = saveregs_value;
   p->apply_args_value = apply_args_value;
   p->forced_labels = forced_labels;
 
   pending_stack_adjust = 0;
   inhibit_defer_pop = 0;
-  cleanups_this_call = 0;
   saveregs_value = 0;
   apply_args_value = 0;
   forced_labels = 0;
@@ -396,7 +389,6 @@ restore_expr_status (p)
 {
   pending_stack_adjust = p->pending_stack_adjust;
   inhibit_defer_pop = p->inhibit_defer_pop;
-  cleanups_this_call = p->cleanups_this_call;
   saveregs_value = p->saveregs_value;
   apply_args_value = p->apply_args_value;
   forced_labels = p->forced_labels;
@@ -611,115 +603,17 @@ convert_move (to, from, unsignedp)
     {
       rtx value;
 
-#ifdef HAVE_extendqfhf2
-      if (HAVE_extendqfhf2 && from_mode == QFmode && to_mode == HFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendqfhf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendqfsf2
-      if (HAVE_extendqfsf2 && from_mode == QFmode && to_mode == SFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendqfsf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendqfdf2
-      if (HAVE_extendqfdf2 && from_mode == QFmode && to_mode == DFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendqfdf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendqfxf2
-      if (HAVE_extendqfxf2 && from_mode == QFmode && to_mode == XFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendqfxf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendqftf2
-      if (HAVE_extendqftf2 && from_mode == QFmode && to_mode == TFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendqftf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-
-#ifdef HAVE_extendhftqf2
-      if (HAVE_extendhftqf2 && from_mode == HFmode && to_mode == TQFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendhftqf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-
-#ifdef HAVE_extendhfsf2
-      if (HAVE_extendhfsf2 && from_mode == HFmode && to_mode == SFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendhfsf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendhfdf2
-      if (HAVE_extendhfdf2 && from_mode == HFmode && to_mode == DFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendhfdf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendhfxf2
-      if (HAVE_extendhfxf2 && from_mode == HFmode && to_mode == XFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendhfxf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendhftf2
-      if (HAVE_extendhftf2 && from_mode == HFmode && to_mode == TFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendhftf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-
-#ifdef HAVE_extendsfdf2
-      if (HAVE_extendsfdf2 && from_mode == SFmode && to_mode == DFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendsfdf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendsfxf2
-      if (HAVE_extendsfxf2 && from_mode == SFmode && to_mode == XFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendsfxf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extendsftf2
-      if (HAVE_extendsftf2 && from_mode == SFmode && to_mode == TFmode)
-       {
-         emit_unop_insn (CODE_FOR_extendsftf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extenddfxf2
-      if (HAVE_extenddfxf2 && from_mode == DFmode && to_mode == XFmode)
-       {
-         emit_unop_insn (CODE_FOR_extenddfxf2, to, from, UNKNOWN);
-         return;
-       }
-#endif
-#ifdef HAVE_extenddftf2
-      if (HAVE_extenddftf2 && from_mode == DFmode && to_mode == TFmode)
+      if (GET_MODE_BITSIZE (from_mode) < GET_MODE_BITSIZE (to_mode))
        {
-         emit_unop_insn (CODE_FOR_extenddftf2, to, from, UNKNOWN);
-         return;
+         /* Try converting directly if the insn is supported.  */
+         if ((code = can_extend_p (to_mode, from_mode, 0))
+             != CODE_FOR_nothing)
+           {
+             emit_unop_insn (code, to, from, UNKNOWN);
+             return;
+           }
        }
-#endif
-
 #ifdef HAVE_trunchfqf2
       if (HAVE_trunchfqf2 && from_mode == HFmode && to_mode == QFmode)
        {
@@ -791,6 +685,36 @@ convert_move (to, from, unsignedp)
          return;
        }
 #endif
+
+#ifdef HAVE_truncsftqf2
+      if (HAVE_truncsftqf2 && from_mode == SFmode && to_mode == TQFmode)
+       {
+         emit_unop_insn (CODE_FOR_truncsftqf2, to, from, UNKNOWN);
+         return;
+       }
+#endif
+#ifdef HAVE_truncdftqf2
+      if (HAVE_truncdftqf2 && from_mode == DFmode && to_mode == TQFmode)
+       {
+         emit_unop_insn (CODE_FOR_truncdftqf2, to, from, UNKNOWN);
+         return;
+       }
+#endif
+#ifdef HAVE_truncxftqf2
+      if (HAVE_truncxftqf2 && from_mode == XFmode && to_mode == TQFmode)
+       {
+         emit_unop_insn (CODE_FOR_truncxftqf2, to, from, UNKNOWN);
+         return;
+       }
+#endif
+#ifdef HAVE_trunctftqf2
+      if (HAVE_trunctftqf2 && from_mode == TFmode && to_mode == TQFmode)
+       {
+         emit_unop_insn (CODE_FOR_trunctftqf2, to, from, UNKNOWN);
+         return;
+       }
+#endif
+
 #ifdef HAVE_truncdfsf2
       if (HAVE_truncdfsf2 && from_mode == DFmode && to_mode == SFmode)
        {
@@ -1359,7 +1283,20 @@ convert_modes (mode, oldmode, x, unsignedp)
   if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
       && GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT
       && GET_CODE (x) == CONST_INT && INTVAL (x) < 0)
-    return immed_double_const (INTVAL (x), (HOST_WIDE_INT) 0, mode);
+    {
+      HOST_WIDE_INT val = INTVAL (x);
+
+      if (oldmode != VOIDmode
+         && HOST_BITS_PER_WIDE_INT > GET_MODE_BITSIZE (oldmode))
+       {
+         int width = GET_MODE_BITSIZE (oldmode);
+
+         /* We need to zero extend VAL.  */
+         val &= ((HOST_WIDE_INT) 1 << width) - 1;
+       }
+
+      return immed_double_const (val, (HOST_WIDE_INT) 0, mode);
+    }
 
   /* We can do this with a gen_lowpart if both desired and current modes
      are integer, and this is either a constant integer, a register, or a
@@ -1517,7 +1454,7 @@ move_by_pieces (to, from, len, align)
     }
 
   /* The code above should have handled everything.  */
-  if (data.len != 0)
+  if (data.len > 0)
     abort ();
 }
 
@@ -1580,14 +1517,17 @@ move_by_pieces_1 (genfun, mode, data)
 
       to1 = (data->autinc_to
             ? gen_rtx (MEM, mode, data->to_addr)
-            : change_address (data->to, mode,
-                              plus_constant (data->to_addr, data->offset)));
+            : copy_rtx (change_address (data->to, mode,
+                                        plus_constant (data->to_addr,
+                                                       data->offset))));
       MEM_IN_STRUCT_P (to1) = data->to_struct;
-      from1 =
-       (data->autinc_from
-        ? gen_rtx (MEM, mode, data->from_addr)
-        : change_address (data->from, mode,
-                          plus_constant (data->from_addr, data->offset)));
+
+      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;
 
 #ifdef HAVE_PRE_DECREMENT
@@ -1771,9 +1711,21 @@ move_block_from_reg (regno, x, nregs, size)
 {
   int i;
   rtx pat, last;
+  enum machine_mode mode;
 
+  /* If SIZE is that of a mode no bigger than a word, just use that
+     mode's store operation.  */
+  if (size <= UNITS_PER_WORD
+      && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode)
+    {
+      emit_move_insn (change_address (x, mode, NULL),
+                     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.  */
+     to the left before storing to memory.  Note that the previous test
+     doesn't handle all cases (e.g. SIZE == 3).  */
   if (size < UNITS_PER_WORD && BYTES_BIG_ENDIAN)
     {
       rtx tem = operand_subword (x, 0, 1, BLKmode);
@@ -1818,6 +1770,105 @@ move_block_from_reg (regno, x, nregs, size)
     }
 }
 
+/* Emit code to move a block Y to a block X, where X is non-consecutive
+   registers represented by a PARALLEL.  */
+
+void
+emit_group_load (x, y)
+     rtx x, y;
+{
+  rtx target_reg, source;
+  int i;
+
+  if (GET_CODE (x) != PARALLEL)
+    abort ();
+
+  /* Check for a NULL entry, used to indicate that the parameter goes
+     both on the stack and in registers.  */
+  if (XEXP (XVECEXP (x, 0, 0), 0))
+    i = 0;
+  else
+    i = 1;
+
+  for (; i < XVECLEN (x, 0); i++)
+    {
+      rtx element = XVECEXP (x, 0, i);
+
+      target_reg = XEXP (element, 0);
+
+      if (GET_CODE (y) == MEM)
+       source = change_address (y, GET_MODE (target_reg),
+                                plus_constant (XEXP (y, 0),
+                                               INTVAL (XEXP (element, 1))));
+      else if (XEXP (element, 1) == const0_rtx)
+       {
+         if (GET_MODE (target_reg) == GET_MODE (y))
+           source = y;
+         /* Allow for the target_reg to be smaller than the input register
+            to allow for AIX with 4 DF arguments after a single SI arg.  The
+            last DF argument will only load 1 word into the integer registers,
+            but load a DF value into the float registers.  */
+         else if ((GET_MODE_SIZE (GET_MODE (target_reg))
+                   <= GET_MODE_SIZE (GET_MODE (y)))
+                  && GET_MODE (target_reg) == word_mode)
+           /* This might be a const_double, so we can't just use SUBREG.  */
+           source = operand_subword (y, 0, 0, VOIDmode);
+         else if (GET_MODE_SIZE (GET_MODE (target_reg))
+                  == GET_MODE_SIZE (GET_MODE (y)))
+           source = gen_lowpart (GET_MODE (target_reg), y);
+         else
+           abort ();       
+       }
+      else
+       abort ();
+
+      emit_move_insn (target_reg, source);
+    }
+}
+
+/* Emit code to move a block Y to a block X, where Y is non-consecutive
+   registers represented by a PARALLEL.  */
+
+void
+emit_group_store (x, y)
+     rtx x, y;
+{
+  rtx source_reg, target;
+  int i;
+
+  if (GET_CODE (y) != PARALLEL)
+    abort ();
+
+  /* Check for a NULL entry, used to indicate that the parameter goes
+     both on the stack and in registers.  */
+  if (XEXP (XVECEXP (y, 0, 0), 0))
+    i = 0;
+  else
+    i = 1;
+
+  for (; i < XVECLEN (y, 0); i++)
+    {
+      rtx element = XVECEXP (y, 0, i);
+
+      source_reg = XEXP (element, 0);
+
+      if (GET_CODE (x) == MEM)
+       target = change_address (x, GET_MODE (source_reg),
+                                plus_constant (XEXP (x, 0),
+                                               INTVAL (XEXP (element, 1))));
+      else if (XEXP (element, 1) == const0_rtx)
+       {
+         target = x;
+         if (GET_MODE (target) != GET_MODE (source_reg))
+           target = gen_lowpart (GET_MODE (source_reg), target);
+       }
+      else
+       abort ();
+
+      emit_move_insn (target, source_reg);
+    }
+}
+
 /* Add a USE expression for REG to the (possibly empty) list pointed
    to by CALL_FUSAGE.  REG must denote a hard register.  */
 
@@ -1851,6 +1902,28 @@ use_regs (call_fusage, regno, nregs)
   for (i = 0; i < nregs; i++)
     use_reg (call_fusage, gen_rtx (REG, reg_raw_mode[regno + i], regno + i));
 }
+
+/* Add USE expressions to *CALL_FUSAGE for each REG contained in the
+   PARALLEL REGS.  This is for calls that pass values in multiple
+   non-contiguous locations.  The Irix 6 ABI has examples of this.  */
+
+void
+use_group_regs (call_fusage, regs)
+     rtx *call_fusage;
+     rtx regs;
+{
+  int i;
+
+  /* Check for a NULL entry, used to indicate that the parameter goes
+     both on the stack and in registers.  */
+  if (XEXP (XVECEXP (regs, 0, 0), 0))
+    i = 0;
+  else
+    i = 1;
+
+  for (; i < XVECLEN (regs, 0); i++)
+    use_reg (call_fusage, XEXP (XVECEXP (regs, 0, i), 0));
+}
 \f
 /* Generate several move instructions to clear LEN bytes of block TO.
    (A MEM rtx with BLKmode).   The caller must pass TO through
@@ -1960,8 +2033,9 @@ clear_by_pieces_1 (genfun, mode, data)
 
       to1 = (data->autinc_to
             ? gen_rtx (MEM, mode, data->to_addr)
-            : change_address (data->to, mode,
-                              plus_constant (data->to_addr, data->offset)));
+            : copy_rtx (change_address (data->to, mode,
+                                        plus_constant (data->to_addr,
+                                                       data->offset))));
       MEM_IN_STRUCT_P (to1) = data->to_struct;
 
 #ifdef HAVE_PRE_DECREMENT
@@ -2643,7 +2717,14 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
      into the appropriate registers.  Do this now, at the end,
      since mem-to-mem copies above may do function calls.  */
   if (partial > 0 && reg != 0)
-    move_block_to_reg (REGNO (reg), x, partial, mode);
+    {
+      /* Handle calls that pass values in multiple non-contiguous locations.
+        The Irix 6 ABI has examples of this.  */
+      if (GET_CODE (reg) == PARALLEL)
+       emit_group_load (reg, x);
+      else
+       move_block_to_reg (REGNO (reg), x, partial, mode);
+    }
 
   if (extra && args_addr == 0 && where_pad == stack_direction)
     anti_adjust_stack (GEN_INT (extra));
@@ -2687,7 +2768,7 @@ expand_assignment (to, from, want_value, suggest_reg)
       dest_innermost = bc_expand_address (to);
 
       /* Can't deduce from TYPE that we're dealing with a bitfield, so
-        take care of it here. */
+        take care of it here.  */
 
       bc_store_memory (TREE_TYPE (to), dest_innermost);
       return NULL;
@@ -2716,8 +2797,8 @@ expand_assignment (to, from, want_value, suggest_reg)
       int alignment;
 
       push_temp_slots ();
-      tem = get_inner_reference (to, &bitsize, &bitpos, &offset,
-                                     &mode1, &unsignedp, &volatilep);
+      tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
+                                &unsignedp, &volatilep, &alignment);
 
       /* If we are going to use store_bit_field and extract_bit_field,
         make sure to_rtx will be safe for multiple use.  */
@@ -2725,7 +2806,6 @@ expand_assignment (to, from, want_value, suggest_reg)
       if (mode1 == VOIDmode && want_value)
        tem = stabilize_reference (tem);
 
-      alignment = TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT;
       to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0);
       if (offset != 0)
        {
@@ -2736,14 +2816,6 @@ expand_assignment (to, from, want_value, suggest_reg)
          to_rtx = change_address (to_rtx, VOIDmode,
                                   gen_rtx (PLUS, ptr_mode, XEXP (to_rtx, 0),
                                            force_reg (ptr_mode, offset_rtx)));
-         /* If we have a variable offset, the known alignment
-            is only that of the innermost structure containing the field.
-            (Actually, we could sometimes do better by using the
-            align of an element of the innermost array, but no need.)  */
-         if (TREE_CODE (to) == COMPONENT_REF
-             || TREE_CODE (to) == BIT_FIELD_REF)
-           alignment
-             = TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (to, 0))) / BITS_PER_UNIT;
        }
       if (volatilep)
        {
@@ -2753,7 +2825,8 @@ expand_assignment (to, from, want_value, suggest_reg)
                 structure we are storing into, and hence may be shared.
                 We must make a new MEM before setting the volatile bit.  */
              if (offset == 0)
-               to_rtx = change_address (to_rtx, VOIDmode, XEXP (to_rtx, 0));
+               to_rtx = copy_rtx (to_rtx);
+
              MEM_VOLATILE_P (to_rtx) = 1;
            }
 #if 0  /* This was turned off because, when a field is volatile
@@ -2797,6 +2870,7 @@ expand_assignment (to, from, want_value, suggest_reg)
      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))
     {
       rtx value;
@@ -2806,7 +2880,11 @@ expand_assignment (to, from, want_value, suggest_reg)
       if (to_rtx == 0)
        to_rtx = expand_expr (to, NULL_RTX, VOIDmode, 0);
 
-      if (GET_MODE (to_rtx) == BLKmode)
+      /* Handle calls that return values in multiple non-contiguous locations.
+        The Irix 6 ABI has examples of this.  */
+      if (GET_CODE (to_rtx) == PARALLEL)
+       emit_group_load (to_rtx, value);
+      else if (GET_MODE (to_rtx) == BLKmode)
        emit_block_move (to_rtx, value, expr_size (from),
                         TYPE_ALIGN (TREE_TYPE (from)) / BITS_PER_UNIT);
       else
@@ -2937,15 +3015,20 @@ store_expr (exp, target, want_value)
       do_pending_stack_adjust ();
       NO_DEFER_POP;
       jumpifnot (TREE_OPERAND (exp, 0), lab1);
+      start_cleanup_deferal ();
       store_expr (TREE_OPERAND (exp, 1), target, 0);
+      end_cleanup_deferal ();
       emit_queue ();
       emit_jump_insn (gen_jump (lab2));
       emit_barrier ();
       emit_label (lab1);
+      start_cleanup_deferal ();
       store_expr (TREE_OPERAND (exp, 2), target, 0);
+      end_cleanup_deferal ();
       emit_queue ();
       emit_label (lab2);
       OK_DEFER_POP;
+
       return want_value ? target : NULL_RTX;
     }
   else if (want_value && GET_CODE (target) == MEM && ! MEM_VOLATILE_P (target)
@@ -2991,8 +3074,11 @@ store_expr (exp, target, want_value)
       /* If we don't want a value, we can do the conversion inside EXP,
         which will often result in some optimizations.  Do the conversion
         in two steps: first change the signedness, if needed, then
-        the extend.  */
-      if (! want_value)
+        the extend.  But don't do this if the type of EXP is a subtype
+        of something else since then the conversion might involve
+        more than just converting modes.  */
+      if (! want_value && INTEGRAL_TYPE_P (TREE_TYPE (exp))
+         && TREE_TYPE (TREE_TYPE (exp)) == 0)
        {
          if (TREE_UNSIGNED (TREE_TYPE (exp))
              != SUBREG_PROMOTED_UNSIGNED_P (target))
@@ -3041,7 +3127,7 @@ store_expr (exp, target, want_value)
       if (!(target && GET_CODE (target) == REG
            && REGNO (target) < FIRST_PSEUDO_REGISTER)
          && !(GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
-         && temp != target
+         && ! rtx_equal_p (temp, target)
          && (CONSTANT_P (temp) || want_value))
        dont_return_target = 1;
     }
@@ -3059,7 +3145,7 @@ store_expr (exp, target, want_value)
   /* If value was not generated in the target, store it there.
      Convert the value to TARGET's type first if nec.  */
 
-  if (temp != target && TREE_CODE (exp) != ERROR_MARK)
+  if (! rtx_equal_p (temp, target) && TREE_CODE (exp) != ERROR_MARK)
     {
       target = protect_from_queue (target, 1);
       if (GET_MODE (temp) != GET_MODE (target)
@@ -3141,7 +3227,7 @@ store_expr (exp, target, want_value)
                {
 #ifdef TARGET_MEM_FUNCTIONS
                  emit_library_call (memset_libfunc, 0, VOIDmode, 3,
-                                    addr, Pmode,
+                                    addr, ptr_mode,
                                     const0_rtx, TYPE_MODE (integer_type_node),
                                     convert_to_mode (TYPE_MODE (sizetype),
                                                      size,
@@ -3149,7 +3235,7 @@ store_expr (exp, target, want_value)
                                     TYPE_MODE (sizetype));
 #else
                  emit_library_call (bzero_libfunc, 0, VOIDmode, 2,
-                                    addr, Pmode,
+                                    addr, ptr_mode,
                                     convert_to_mode (TYPE_MODE (integer_type_node),
                                                      size,
                                                      TREE_UNSIGNED (integer_type_node)),
@@ -3161,6 +3247,10 @@ store_expr (exp, target, want_value)
                emit_label (label);
            }
        }
+      /* Handle calls that return values in multiple non-contiguous locations.
+        The Irix 6 ABI has examples of this.  */
+      else if (GET_CODE (target) == PARALLEL)
+       emit_group_load (target, temp);
       else if (GET_MODE (temp) == BLKmode)
        emit_block_move (target, temp, expr_size (exp),
                         TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
@@ -3246,7 +3336,7 @@ mostly_zeros_p (exp)
             so the statistic will be somewhat inaccurate.
             We do make a more accurate count in store_constructor itself,
             so since this function is only used for nested array elements,
-            this should be close enough. */
+            this should be close enough.  */
          if (mostly_zeros_p (TREE_VALUE (elt)))
            zeros++;
          elts++;
@@ -3261,7 +3351,12 @@ mostly_zeros_p (exp)
 /* Helper function for store_constructor.
    TARGET, BITSIZE, BITPOS, MODE, EXP are as for store_field.
    TYPE is the type of the CONSTRUCTOR, not the element type.
-   CLEARED is as for store_constructor.  */
+   CLEARED is as for store_constructor.
+
+   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
+   the cleared field to let store_constructor know that we may not have to
+   clear a substructure if the outer structure has already been cleared.  */
 
 static void
 store_constructor_field (target, bitsize, bitpos,
@@ -3273,7 +3368,11 @@ store_constructor_field (target, bitsize, bitpos,
      int cleared;
 {
   if (TREE_CODE (exp) == CONSTRUCTOR
-      && (bitpos % BITS_PER_UNIT) == 0)
+      && bitpos % BITS_PER_UNIT == 0
+      /* If we have a non-zero bitpos for a register target, then we just
+        let store_field do the bitfield handling.  This is unlikely to
+        generate unnecessary clear instructions anyways.  */
+      && (bitpos == 0 || GET_CODE (target) == MEM))
     {
       if (bitpos != 0)
        target = change_address (target, VOIDmode,
@@ -3289,7 +3388,7 @@ store_constructor_field (target, bitsize, bitpos,
 
 /* Store the value of constructor EXP into the rtx TARGET.
    TARGET is either a REG or a MEM.
-   CLEARED is true if TARGET is known to have been zero'd. */
+   CLEARED is true if TARGET is known to have been zero'd.  */
 
 static void
 store_constructor (exp, target, cleared)
@@ -3416,8 +3515,8 @@ store_constructor (exp, target, cleared)
          if (TREE_READONLY (field))
            {
              if (GET_CODE (to_rtx) == MEM)
-               to_rtx = change_address (to_rtx, GET_MODE (to_rtx),
-                                        XEXP (to_rtx, 0));
+               to_rtx = copy_rtx (to_rtx);
+
              RTX_UNCHANGING_P (to_rtx) = 1;
            }
 
@@ -3449,7 +3548,7 @@ store_constructor (exp, target, cleared)
             It is also needed to check for missing elements.  */
          for (elt = CONSTRUCTOR_ELTS (exp);
               elt != NULL_TREE;
-              elt = TREE_CHAIN (elt), i++)
+              elt = TREE_CHAIN (elt))
            {
              tree index = TREE_PURPOSE (elt);
              HOST_WIDE_INT this_node_count;
@@ -3472,7 +3571,10 @@ store_constructor (exp, target, cleared)
              if (mostly_zeros_p (TREE_VALUE (elt)))
                zero_count += this_node_count;
            }
-         if (4 * zero_count >= 3 * 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)
            need_to_clear = 1;
        }
       if (need_to_clear)
@@ -3514,30 +3616,27 @@ store_constructor (exp, target, cleared)
              tree hi_index = TREE_OPERAND (index, 1);
              rtx index_r, pos_rtx, addr, hi_r, loop_top, loop_end;
              struct nesting *loop;
-               tree position;
+             HOST_WIDE_INT lo, hi, count;
+             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)
+                 && TREE_CODE (hi_index) == INTEGER_CST
+                 && (lo = TREE_INT_CST_LOW (lo_index),
+                     hi = TREE_INT_CST_LOW (hi_index),
+                     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_WIDE_INT lo = TREE_INT_CST_LOW (lo_index);
-                 HOST_WIDE_INT hi = TREE_INT_CST_LOW (hi_index);
-                 HOST_WIDE_INT count = hi - lo + 1;
-
-                 /* If the range is constant and "small", unroll the loop.
-                    We must also use store_field if the target is not MEM. */
-                 if (GET_CODE (target) != MEM
-                     || count <= 2
-                     || (TREE_CODE (TYPE_SIZE (elttype)) == INTEGER_CST
-                         && TREE_INT_CST_LOW (TYPE_SIZE (elttype)) * count
-                         <= 40 * 8))
+                 lo -= minelt;  hi -= minelt;
+                 for (; lo <= hi; lo++)
                    {
-                     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, cleared);
-                       }
+                     bitpos = lo * TREE_INT_CST_LOW (TYPE_SIZE (elttype));
+                     store_constructor_field (target, bitsize, bitpos,
+                                              mode, value, type, cleared);
                    }
                }
              else
@@ -3557,14 +3656,15 @@ store_constructor (exp, target, cleared)
                  if (TREE_CODE (value) == SAVE_EXPR
                      && SAVE_EXPR_RTL (value) == 0)
                    {
-                     /* Make sure value gets expanded once before the loop. */
+                     /* Make sure value gets expanded once before the
+                         loop.  */
                      expand_expr (value, const0_rtx, VOIDmode, 0);
                      emit_queue ();
                    }
                  store_expr (lo_index, index_r, 0);
                  loop = expand_start_loop (0);
 
-                 /* Assign value to element index. */
+                 /* Assign value to element index.  */
                  position = size_binop (EXACT_DIV_EXPR, TYPE_SIZE (elttype),
                                         size_int (BITS_PER_UNIT));
                  position = size_binop (MULT_EXPR,
@@ -3575,7 +3675,7 @@ store_constructor (exp, target, cleared)
                  addr = gen_rtx (PLUS, Pmode, XEXP (target, 0), pos_rtx);
                  xtarget = change_address (target, mode, addr);
                  if (TREE_CODE (value) == CONSTRUCTOR)
-                   store_constructor (exp, xtarget, cleared);
+                   store_constructor (value, xtarget, cleared);
                  else
                    store_expr (value, xtarget, 0);
 
@@ -3585,7 +3685,7 @@ store_constructor (exp, target, cleared)
 
                  expand_increment (build (PREINCREMENT_EXPR,
                                           TREE_TYPE (index),
-                                          index, integer_one_node), 0);
+                                          index, integer_one_node), 0, 0);
                  expand_end_loop ();
                  emit_label (loop_end);
 
@@ -3645,9 +3745,9 @@ store_constructor (exp, target, cleared)
         probably better to set it using memset (if available) or bzero.
         Also, if a large set has just a single range, it may also be
         better to first clear all the first clear the set (using
-        bzero/memset), and set the bits we want. */
+        bzero/memset), and set the bits we want.  */
        
-      /* Check for all zeros. */
+      /* Check for all zeros.  */
       if (elt == NULL_TREE)
        {
          if (!cleared)
@@ -3674,11 +3774,11 @@ store_constructor (exp, target, cleared)
        {
          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);
+         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. */
+         int offset = 0;  /* In bytes from beginning of set.  */
          elt = get_set_constructor_bits (exp, bit_buffer, nbits);
          for (;;)
            {
@@ -3696,8 +3796,9 @@ store_constructor (exp, target, 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. */
+                     /* The assumption here is that it is safe to use
+                        XEXP if the set is multi-word, but not if
+                        it's single-word.  */
                      if (GET_CODE (target) == MEM)
                        {
                          to_rtx = plus_constant (XEXP (target, 0), offset);
@@ -3719,7 +3820,7 @@ store_constructor (exp, target, cleared)
        }
       else if (!cleared)
        {
-         /* Don't bother clearing storage if the set is all ones. */
+         /* Don't bother clearing storage if the set is all ones.  */
          if (TREE_CHAIN (elt) != NULL_TREE
              || (TREE_PURPOSE (elt) == NULL_TREE
                  ? nbits != 1
@@ -3777,7 +3878,7 @@ store_constructor (exp, target, cleared)
 #ifdef TARGET_MEM_FUNCTIONS
          /* Optimization:  If startbit and endbit are
             constants divisible by BITS_PER_UNIT,
-            call memset instead. */
+            call memset instead.  */
          if (TREE_CODE (startbit) == INTEGER_CST
              && TREE_CODE (endbit) == INTEGER_CST
              && (startb = TREE_INT_CST_LOW (startbit)) % BITS_PER_UNIT == 0
@@ -3893,12 +3994,45 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
     {
       rtx temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
 
+      /* If BITSIZE is narrower than the size of the type of EXP
+        we will be narrowing TEMP.  Normally, what's wanted are the
+        low-order bits.  However, if EXP's type is a record and this is
+        big-endian machine, we want the upper BITSIZE bits.  */
+      if (BYTES_BIG_ENDIAN && GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
+         && bitsize < GET_MODE_BITSIZE (GET_MODE (temp))
+         && TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
+       temp = expand_shift (RSHIFT_EXPR, GET_MODE (temp), temp,
+                            size_int (GET_MODE_BITSIZE (GET_MODE (temp))
+                                      - bitsize),
+                            temp, 1);
+
       /* Unless MODE is VOIDmode or BLKmode, convert TEMP to
         MODE.  */
       if (mode != VOIDmode && mode != BLKmode
          && mode != TYPE_MODE (TREE_TYPE (exp)))
        temp = convert_modes (mode, TYPE_MODE (TREE_TYPE (exp)), temp, 1);
 
+      /* If the modes of TARGET and TEMP are both BLKmode, both
+        must be in memory and BITPOS must be aligned on a byte
+        boundary.  If so, we simply do a block copy.  */
+      if (GET_MODE (target) == BLKmode && GET_MODE (temp) == BLKmode)
+       {
+         if (GET_CODE (target) != MEM || GET_CODE (temp) != MEM
+             || bitpos % BITS_PER_UNIT != 0)
+           abort ();
+
+         target = change_address (target, VOIDmode,
+                                  plus_constant (XEXP (target, 0),
+                                               bitpos / BITS_PER_UNIT));
+
+         emit_block_move (target, temp,
+                          GEN_INT ((bitsize + BITS_PER_UNIT - 1)
+                                   / BITS_PER_UNIT),
+                          1);
+
+         return value_mode == VOIDmode ? const0_rtx : target;
+       }
+
       /* Store the value in the bitfield.  */
       store_bit_field (target, bitsize, bitpos, mode, temp, align, total_size);
       if (value_mode != VOIDmode)
@@ -3945,8 +4079,10 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
 
       /* Now build a reference to just the desired component.  */
 
-      to_rtx = change_address (target, mode,
-                              plus_constant (addr, (bitpos / BITS_PER_UNIT)));
+      to_rtx = copy_rtx (change_address (target, mode,
+                                        plus_constant (addr,
+                                                       (bitpos
+                                                        / BITS_PER_UNIT))));
       MEM_IN_STRUCT_P (to_rtx) = 1;
 
       return store_expr (exp, to_rtx, value_mode != VOIDmode);
@@ -3994,6 +4130,9 @@ get_inner_unaligned_p (exp)
    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
+   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.
 
    If any of the extraction expressions is volatile,
    we store 1 in *PVOLATILEP.  Otherwise we don't change that.
@@ -4004,11 +4143,11 @@ get_inner_unaligned_p (exp)
 
    If the field describes a variable-sized object, *PMODE is set to
    VOIDmode and *PBITSIZE is set to -1.  An access cannot be made in
-   this case, but the address of the object can be found.  */
+   this case, but the address of the object can be found.   */
 
 tree
 get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
-                    punsignedp, pvolatilep)
+                    punsignedp, pvolatilep, palignment)
      tree exp;
      int *pbitsize;
      int *pbitpos;
@@ -4016,11 +4155,13 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
      enum machine_mode *pmode;
      int *punsignedp;
      int *pvolatilep;
+     int *palignment;
 {
   tree orig_exp = exp;
   tree size_tree = 0;
   enum machine_mode mode = VOIDmode;
   tree offset = integer_zero_node;
+  int alignment = BIGGEST_ALIGNMENT;
 
   if (TREE_CODE (exp) == COMPONENT_REF)
     {
@@ -4078,11 +4219,9 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
            constant = pos, var = integer_zero_node;
 
          *pbitpos += TREE_INT_CST_LOW (constant);
-
-         if (var)
-           offset = size_binop (PLUS_EXPR, offset,
-                                size_binop (EXACT_DIV_EXPR, var,
-                                            size_int (BITS_PER_UNIT)));
+         offset = size_binop (PLUS_EXPR, offset,
+                              size_binop (EXACT_DIV_EXPR, var,
+                                          size_int (BITS_PER_UNIT)));
        }
 
       else if (TREE_CODE (exp) == ARRAY_REF)
@@ -4108,7 +4247,8 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
            }
 
          index = fold (build (MULT_EXPR, index_type, index,
-                              TYPE_SIZE (TREE_TYPE (exp))));
+                              convert (index_type,
+                                       TYPE_SIZE (TREE_TYPE (exp)))));
 
          if (TREE_CODE (index) == INTEGER_CST
              && TREE_INT_CST_HIGH (index) == 0)
@@ -4131,17 +4271,19 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
       /* If any reference in the chain is volatile, the effect is volatile.  */
       if (TREE_THIS_VOLATILE (exp))
        *pvolatilep = 1;
+
+      /* If the offset is non-constant already, then we can't assume any
+        alignment more than the alignment here.  */
+      if (! integer_zerop (offset))
+       alignment = MIN (alignment, TYPE_ALIGN (TREE_TYPE (exp)));
+
       exp = TREE_OPERAND (exp, 0);
     }
 
-  /* If this was a bit-field, see if there is a mode that allows direct
-     access in case EXP is in memory.  */
-  if (mode == VOIDmode && *pbitsize != 0 && *pbitpos % *pbitsize == 0)
-    {
-      mode = mode_for_size (*pbitsize, MODE_INT, 0);
-      if (mode == BLKmode)
-       mode = VOIDmode;
-    }
+  if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'd')
+    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;
@@ -4151,6 +4293,7 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
 
   *pmode = mode;
   *poffset = offset;
+  *palignment = alignment / BITS_PER_UNIT;
   return exp;
 }
 \f
@@ -4302,12 +4445,17 @@ safe_from_p (x, exp)
 
   if (x == 0
       /* If EXP has varying size, we MUST use a target since we currently
-        have no way of allocating temporaries of variable size.  So we
-        assume here that something at a higher level has prevented a
+        have no way of allocating temporaries of variable size
+        (except for arrays that have TYPE_ARRAY_MAX_SIZE set).
+        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.  */
       || (TREE_TYPE (exp) != 0 && TYPE_SIZE (TREE_TYPE (exp)) != 0
          && 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
+             || TREE_CODE (TYPE_ARRAY_MAX_SIZE (TREE_TYPE (exp)))
+             != INTEGER_CST)
          && GET_MODE (x) == BLKmode))
     return 1;
 
@@ -4411,7 +4559,7 @@ safe_from_p (x, exp)
          return safe_from_p (x, TREE_OPERAND (exp, 1));
 
        case METHOD_CALL_EXPR:
-         /* This takes a rtx argument, but shouldn't appear here. */
+         /* This takes a rtx argument, but shouldn't appear here.  */
          abort ();
        }
 
@@ -4464,6 +4612,24 @@ fixed_type_p (exp)
     return 1;
   return 0;
 }
+
+/* Subroutine of expand_expr: return rtx if EXP is a
+   variable or parameter; else return 0.  */
+
+static rtx
+var_rtx (exp)
+     tree exp;
+{
+  STRIP_NOPS (exp);
+  switch (TREE_CODE (exp))
+    {
+    case PARM_DECL:
+    case VAR_DECL:
+      return DECL_RTL (exp);
+    default:
+      return 0;
+    }
+}
 \f
 /* expand_expr: generate code for computing expression EXP.
    An rtx for the computed value is returned.  The value is never null.
@@ -4578,7 +4744,7 @@ expand_expr (exp, target, tmode, modifier)
       else if ((code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
               && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 1)))
        /* If the second operand has no side effects, just evaluate
-          the first. */
+          the first.  */
        return expand_expr (TREE_OPERAND (exp, 0), const0_rtx,
                            VOIDmode, modifier);
 
@@ -4629,7 +4795,7 @@ expand_expr (exp, target, tmode, modifier)
          return CONST0_RTX (mode);
        }
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case VAR_DECL:
       /* If a static var's type was incomplete when the decl was written,
@@ -4644,7 +4810,7 @@ expand_expr (exp, target, tmode, modifier)
          pop_obstacks ();
        }
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case FUNCTION_DECL:
     case RESULT_DECL:
@@ -4681,6 +4847,8 @@ expand_expr (exp, target, tmode, modifier)
 
          /* Mark as non-local and addressable.  */
          DECL_NONLOCAL (exp) = 1;
+         if (DECL_NO_STATIC_CHAIN (current_function_decl))
+           abort ();
          mark_addressable (exp);
          if (GET_CODE (DECL_RTL (exp)) != MEM)
            abort ();
@@ -4846,7 +5014,7 @@ expand_expr (exp, target, tmode, modifier)
 
       /* If the mode of SAVE_EXPR_RTL does not match that of the expression, it
         must be a promoted value.  We return a SUBREG of the wanted mode,
-        but mark it so that we know that it was already extended. */
+        but mark it so that we know that it was already extended.  */
 
       if (GET_CODE (SAVE_EXPR_RTL (exp)) == REG
          && GET_MODE (SAVE_EXPR_RTL (exp)) != mode)
@@ -4861,28 +5029,47 @@ expand_expr (exp, target, tmode, modifier)
 
       return SAVE_EXPR_RTL (exp);
 
+    case UNSAVE_EXPR:
+      {
+       rtx temp;
+       temp = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
+       TREE_OPERAND (exp, 0) = unsave_expr_now (TREE_OPERAND (exp, 0));
+       return temp;
+      }
+
     case PLACEHOLDER_EXPR:
       /* If there is an object on the head of the placeholder list,
         see if some object in it's references is of type TYPE.  For
         further information, see tree.def.  */
       if (placeholder_list)
        {
-         tree object;
+         tree need_type = TYPE_MAIN_VARIANT (type);
+         tree object = 0;
          tree old_list = placeholder_list;
+         tree elt;
 
-         for (object = TREE_PURPOSE (placeholder_list);
-              (TYPE_MAIN_VARIANT (TREE_TYPE (object))
-               != TYPE_MAIN_VARIANT (type))
-              && (TREE_CODE_CLASS (TREE_CODE (object)) == 'r'
-                  || TREE_CODE_CLASS (TREE_CODE (object)) == '1'
-                  || TREE_CODE_CLASS (TREE_CODE (object)) == '2'
-                  || TREE_CODE_CLASS (TREE_CODE (object)) == 'e');
-              object = TREE_OPERAND (object, 0))
-           ;
-
-         if (object != 0
-             && (TYPE_MAIN_VARIANT (TREE_TYPE (object))
-                 == TYPE_MAIN_VARIANT (type)))
+         /* See if the object is the type that we want.  Then see if
+            the operand of any reference is the type we want.  */
+         if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_PURPOSE (placeholder_list)))
+              == need_type))
+           object = TREE_PURPOSE (placeholder_list);
+
+         /* Find the innermost reference that is of the type we want.    */
+         for (elt = TREE_PURPOSE (placeholder_list);
+              elt != 0
+              && (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+                  || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+                  || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+                  || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e');
+              elt = ((TREE_CODE (elt) == COMPOUND_EXPR
+                      || TREE_CODE (elt) == COND_EXPR)
+                     ? TREE_OPERAND (elt, 1) : TREE_OPERAND (elt, 0)))
+           if (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+               && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (elt, 0)))
+                   == need_type))
+             object = TREE_OPERAND (elt, 0);
+
+         if (object != 0)
            {
              /* Expand this object skipping the list entries before
                 it was found in case it is also a PLACEHOLDER_EXPR.
@@ -4928,7 +5115,7 @@ expand_expr (exp, target, tmode, modifier)
        int vars_need_expansion = 0;
 
        /* Need to open a binding contour here because
-          if there are any cleanups they most be contained here.  */
+          if there are any cleanups they must be contained here.  */
        expand_start_bindings (0);
 
        /* Mark the corresponding BLOCK for output in its proper place.  */
@@ -4956,10 +5143,13 @@ expand_expr (exp, target, tmode, modifier)
       }
 
     case RTL_EXPR:
-      if (RTL_EXPR_SEQUENCE (exp) == const0_rtx)
-       abort ();
-      emit_insns (RTL_EXPR_SEQUENCE (exp));
-      RTL_EXPR_SEQUENCE (exp) = const0_rtx;
+      if (RTL_EXPR_SEQUENCE (exp))
+       {
+         if (RTL_EXPR_SEQUENCE (exp) == const0_rtx)
+           abort ();
+         emit_insns (RTL_EXPR_SEQUENCE (exp));
+         RTL_EXPR_SEQUENCE (exp) = const0_rtx;
+       }
       preserve_rtl_expr_result (RTL_EXPR_RTL (exp));
       free_temps_for_rtl_expr (exp);
       return RTL_EXPR_RTL (exp);
@@ -5009,7 +5199,10 @@ expand_expr (exp, target, tmode, modifier)
 
       else
        {
-         if (target == 0 || ! safe_from_p (target, exp))
+         /* Handle calls that pass values in multiple non-contiguous
+            locations.  The Irix 6 ABI has examples of this.  */
+         if (target == 0 || ! safe_from_p (target, exp)
+             || GET_CODE (target) == PARALLEL)
            {
              if (mode != BLKmode && ! TREE_ADDRESSABLE (exp))
                target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
@@ -5020,8 +5213,8 @@ expand_expr (exp, target, tmode, modifier)
          if (TREE_READONLY (exp))
            {
              if (GET_CODE (target) == MEM)
-               target = change_address (target, GET_MODE (target),
-                                        XEXP (target, 0));
+               target = copy_rtx (target);
+
              RTX_UNCHANGING_P (target) = 1;
            }
 
@@ -5034,27 +5227,8 @@ expand_expr (exp, target, tmode, modifier)
        tree exp1 = TREE_OPERAND (exp, 0);
        tree exp2;
 
-       /* A SAVE_EXPR as the address in an INDIRECT_EXPR is generated
-          for  *PTR += ANYTHING  where PTR is put inside the SAVE_EXPR.
-          This code has the same general effect as simply doing
-          expand_expr on the save expr, except that the expression PTR
-          is computed for use as a memory address.  This means different
-          code, suitable for indexing, may be generated.  */
-       if (TREE_CODE (exp1) == SAVE_EXPR
-           && SAVE_EXPR_RTL (exp1) == 0
-           && TYPE_MODE (TREE_TYPE (exp1)) == ptr_mode)
-         {
-           temp = expand_expr (TREE_OPERAND (exp1, 0), NULL_RTX,
-                               VOIDmode, EXPAND_SUM);
-           op0 = memory_address (mode, temp);
-           op0 = copy_all_regs (op0);
-           SAVE_EXPR_RTL (exp1) = op0;
-         }
-       else
-         {
-           op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
-           op0 = memory_address (mode, op0);
-         }
+       op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
+       op0 = memory_address (mode, op0);
 
        temp = gen_rtx (MEM, mode, op0);
        /* If address was computed by addition,
@@ -5122,7 +5296,7 @@ expand_expr (exp, target, tmode, modifier)
               for any array for which this case will be reached.  */
 
            /* Don't forget the const or volatile flag from the array
-              element. */
+              element.  */
            tree variant_type = build_type_variant (type,
                                                    TREE_READONLY (exp),
                                                    TREE_THIS_VOLATILE (exp));
@@ -5251,8 +5425,46 @@ expand_expr (exp, target, tmode, modifier)
 
          for (elt = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); elt;
               elt = TREE_CHAIN (elt))
-           if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1))
-             return expand_expr (TREE_VALUE (elt), target, tmode, modifier);
+           if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1)
+               /* We can normally use the value of the field in the
+                  CONSTRUCTOR.  However, if this is a bitfield in
+                  an integral mode that we can fit in a HOST_WIDE_INT,
+                  we must mask only the number of bits in the bitfield,
+                  since this is done implicitly by the constructor.  If
+                  the bitfield does not meet either of those conditions,
+                  we can't do this optimization.  */
+               && (! DECL_BIT_FIELD (TREE_PURPOSE (elt))
+                   || ((GET_MODE_CLASS (DECL_MODE (TREE_PURPOSE (elt)))
+                        == MODE_INT)
+                       && (GET_MODE_BITSIZE (DECL_MODE (TREE_PURPOSE (elt)))
+                           <= HOST_BITS_PER_WIDE_INT))))
+             {
+               op0 =  expand_expr (TREE_VALUE (elt), target, tmode, modifier);
+               if (DECL_BIT_FIELD (TREE_PURPOSE (elt)))
+                 {
+                   int bitsize = DECL_FIELD_SIZE (TREE_PURPOSE (elt));
+                   enum machine_mode imode
+                     = TYPE_MODE (TREE_TYPE (TREE_PURPOSE (elt)));
+
+                   if (TREE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
+                     {
+                       op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1);
+                       op0 = expand_and (op0, op1, target);
+                     }
+                   else
+                     {
+                       tree count
+                         = build_int_2 (imode - bitsize, 0);
+
+                       op0 = expand_shift (LSHIFT_EXPR, imode, op0, count,
+                                           target, 0);
+                       op0 = expand_shift (RSHIFT_EXPR, imode, op0, count,
+                                           target, 0);
+                     }
+                 }
+
+               return op0;
+             }
        }
 
       {
@@ -5261,9 +5473,10 @@ expand_expr (exp, target, tmode, modifier)
        int bitpos;
        tree offset;
        int volatilep = 0;
-       tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
-                                       &mode1, &unsignedp, &volatilep);
        int alignment;
+       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
@@ -5294,7 +5507,6 @@ expand_expr (exp, target, tmode, modifier)
              op0 = validize_mem (force_const_mem (mode, op0));
          }
 
-       alignment = TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT;
        if (offset != 0)
          {
            rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
@@ -5304,14 +5516,6 @@ expand_expr (exp, target, tmode, modifier)
            op0 = change_address (op0, VOIDmode,
                                  gen_rtx (PLUS, ptr_mode, XEXP (op0, 0),
                                           force_reg (ptr_mode, offset_rtx)));
-         /* If we have a variable offset, the known alignment
-            is only that of the innermost structure containing the field.
-            (Actually, we could sometimes do better by using the
-            size of an element of the innermost array, but no need.)  */
-         if (TREE_CODE (exp) == COMPONENT_REF
-             || TREE_CODE (exp) == BIT_FIELD_REF)
-           alignment = (TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0)))
-                        / BITS_PER_UNIT);
          }
 
        /* Don't forget about volatility even if this is a bitfield.  */
@@ -5326,13 +5530,16 @@ expand_expr (exp, target, tmode, modifier)
           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.  */
+          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
            || (modifier != EXPAND_CONST_ADDRESS
-               && modifier != EXPAND_SUM
                && modifier != EXPAND_INITIALIZER
-               && ((mode1 != BLKmode && ! direct_load[(int) mode1])
+               && ((mode1 != BLKmode && ! direct_load[(int) mode1]
+                    && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
+                    && 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
@@ -5345,7 +5552,27 @@ expand_expr (exp, target, tmode, modifier)
              ext_mode = mode_for_size (bitsize, MODE_INT, 1);
 
            if (ext_mode == BLKmode)
-             abort ();
+             {
+               /* In this case, BITPOS must start at a byte boundary and
+                  TARGET, if specified, must be a MEM.  */
+               if (GET_CODE (op0) != MEM
+                   || (target != 0 && GET_CODE (target) != MEM)
+                   || bitpos % BITS_PER_UNIT != 0)
+                 abort ();
+
+               op0 = change_address (op0, VOIDmode,
+                                     plus_constant (XEXP (op0, 0),
+                                                    bitpos / BITS_PER_UNIT));
+               if (target == 0)
+                 target = assign_temp (type, 0, 1, 1);
+
+               emit_block_move (target, op0,
+                                GEN_INT ((bitsize + BITS_PER_UNIT - 1)
+                                         / BITS_PER_UNIT),
+                                1);
+               
+               return target;
+             }
 
            op0 = validize_mem (op0);
 
@@ -5356,6 +5583,18 @@ expand_expr (exp, target, tmode, modifier)
                                     unsignedp, target, 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);
+
            if (mode == BLKmode)
              {
                rtx new = assign_stack_temp (ext_mode,
@@ -5389,30 +5628,17 @@ expand_expr (exp, target, tmode, modifier)
 
        MEM_IN_STRUCT_P (op0) = 1;
        MEM_VOLATILE_P (op0) |= volatilep;
-       if (mode == mode1 || mode1 == BLKmode || mode1 == tmode)
+       if (mode == mode1 || mode1 == BLKmode || mode1 == tmode
+           || modifier == EXPAND_CONST_ADDRESS
+           || modifier == EXPAND_INITIALIZER)
          return op0;
-       if (target == 0)
+       else if (target == 0)
          target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
+
        convert_move (target, op0, unsignedp);
        return target;
       }
 
-    case OFFSET_REF:
-      {
-       tree base = build1 (ADDR_EXPR, type, TREE_OPERAND (exp, 0));
-       tree addr = build (PLUS_EXPR, type, base, TREE_OPERAND (exp, 1));
-       op0 = expand_expr (addr, NULL_RTX, VOIDmode, EXPAND_SUM);
-       temp = gen_rtx (MEM, mode, memory_address (mode, op0));
-       MEM_IN_STRUCT_P (temp) = 1;
-       MEM_VOLATILE_P (temp) = TREE_THIS_VOLATILE (exp);
-#if 0 /* It is incorrect to set RTX_UNCHANGING_P here, because the fact that
-        a location is accessed through a pointer to const does not mean
-        that the value there can never change.  */
-       RTX_UNCHANGING_P (temp) = TREE_READONLY (exp);
-#endif
-       return temp;
-      }
-
       /* Intended for a reference to a buffer of a file-object in Pascal.
         But it's not certain that a special tree code will really be
         necessary for these.  INDIRECT_REF might work for them.  */
@@ -5533,30 +5759,28 @@ expand_expr (exp, target, tmode, modifier)
        {
          RTL_EXPR_RTL (exp)
            = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
-         cleanups_this_call
-           = tree_cons (NULL_TREE, TREE_OPERAND (exp, 2), cleanups_this_call);
+         expand_decl_cleanup (NULL_TREE, TREE_OPERAND (exp, 2));
+
          /* That's it for this cleanup.  */
          TREE_OPERAND (exp, 2) = 0;
-         (*interim_eh_hook) (NULL_TREE);
        }
       return RTL_EXPR_RTL (exp);
 
     case CLEANUP_POINT_EXPR:
       {
        extern int temp_slot_level;
-       tree old_cleanups = cleanups_this_call;
-       int old_temp_level = target_temp_slot_level;
-       push_temp_slots ();
+       /* Start a new binding layer that will keep track of all cleanup
+          actions to be performed.  */
+       expand_start_bindings (0);
+
        target_temp_slot_level = temp_slot_level;
+
        op0 = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
        /* If we're going to use this value, load it up now.  */
        if (! ignore)
          op0 = force_not_mem (op0);
-       expand_cleanups_to (old_cleanups);
        preserve_temp_slots (op0);
-       free_temp_slots ();
-       pop_temp_slots ();
-       target_temp_slot_level = old_temp_level;
+       expand_end_bindings (NULL_TREE, 0, 0);
       }
       return op0;
 
@@ -5646,7 +5870,8 @@ expand_expr (exp, target, tmode, modifier)
       return target;
 
     case PLUS_EXPR:
-      /* We come here from MINUS_EXPR when the second operand is a constant. */
+      /* We come here from MINUS_EXPR when the second operand is a
+         constant.  */
     plus_expr:
       this_optab = add_optab;
 
@@ -6165,7 +6390,7 @@ expand_expr (exp, target, tmode, modifier)
       if (temp != 0)
        return temp;
 
-      /* For foo != 0, load foo, and if it is nonzero load 1 instead. */
+      /* For foo != 0, load foo, and if it is nonzero load 1 instead.  */
       if (code == NE_EXPR && integer_zerop (TREE_OPERAND (exp, 1))
          && original_target
          && GET_CODE (original_target) == REG
@@ -6231,18 +6456,32 @@ expand_expr (exp, target, tmode, modifier)
                          VOIDmode, 0);
 
     case COND_EXPR:
-      {
-       rtx flag = NULL_RTX;
-       tree left_cleanups = NULL_TREE;
-       tree right_cleanups = NULL_TREE;
-
-       /* Used to save a pointer to the place to put the setting of
-          the flag that indicates if this side of the conditional was
-          taken.  We backpatch the code, if we find out later that we
-          have any conditional cleanups that need to be performed. */
-       rtx dest_right_flag = NULL_RTX;
-       rtx dest_left_flag = NULL_RTX;
+      /* If we would have a "singleton" (see below) were it not for a
+        conversion in each arm, bring that conversion back out.  */
+      if (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
+         && TREE_CODE (TREE_OPERAND (exp, 2)) == NOP_EXPR
+         && (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0))
+             == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 2), 0))))
+       {
+         tree true = TREE_OPERAND (TREE_OPERAND (exp, 1), 0);
+         tree false = TREE_OPERAND (TREE_OPERAND (exp, 2), 0);
+
+         if ((TREE_CODE_CLASS (TREE_CODE (true)) == '2'
+              && operand_equal_p (false, TREE_OPERAND (true, 0), 0))
+             || (TREE_CODE_CLASS (TREE_CODE (false)) == '2'
+                 && operand_equal_p (true, TREE_OPERAND (false, 0), 0))
+             || (TREE_CODE_CLASS (TREE_CODE (true)) == '1'
+                 && operand_equal_p (false, TREE_OPERAND (true, 0), 0))
+             || (TREE_CODE_CLASS (TREE_CODE (false)) == '1'
+                 && operand_equal_p (true, TREE_OPERAND (false, 0), 0)))
+           return expand_expr (build1 (NOP_EXPR, type,
+                                       build (COND_EXPR, TREE_TYPE (true),
+                                              TREE_OPERAND (exp, 0),
+                                              true, false)),
+                               target, tmode, modifier);
+       }
 
+      {
        /* Note that COND_EXPRs whose type is a structure or union
           are required to be constructed to contain assignments of
           a temporary variable, so that we can evaluate them here
@@ -6253,7 +6492,6 @@ expand_expr (exp, target, tmode, modifier)
 
        tree singleton = 0;
        tree binary_op = 0, unary_op = 0;
-       tree old_cleanups = cleanups_this_call;
 
        /* If this is (A ? 1 : 0) and A is a condition, just evaluate it and
           convert it to our mode, if necessary.  */
@@ -6278,27 +6516,11 @@ expand_expr (exp, target, tmode, modifier)
            return target;
          }
 
-       /* If we are not to produce a result, we have no target.  Otherwise,
-          if a target was specified use it; it will not be used as an
-          intermediate target unless it is safe.  If no target, use a 
-          temporary.  */
-
-       if (ignore)
-         temp = 0;
-       else if (original_target
-                && safe_from_p (original_target, TREE_OPERAND (exp, 0))
-                && GET_MODE (original_target) == mode
-                && ! (GET_CODE (original_target) == MEM
-                      && MEM_VOLATILE_P (original_target)))
-         temp = original_target;
-       else
-         temp = assign_temp (type, 0, 0, 1);
-
-       /* Check for X ? A + B : A.  If we have this, we can copy
-          A to the output and conditionally add B.  Similarly for unary
-          operations.  Don't do this if X has side-effects because
-          those side effects might affect A or B and the "?" operation is
-          a sequence point in ANSI.  (We test for side effects later.)  */
+       /* Check for X ? A + B : A.  If we have this, we can copy A to the
+          output and conditionally add B.  Similarly for unary operations.
+          Don't do this if X has side-effects because those side effects
+          might affect A or B and the "?" operation is a sequence point in
+          ANSI.  (operand_equal_p tests for side effects.)  */
 
        if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 1))) == '2'
            && operand_equal_p (TREE_OPERAND (exp, 2),
@@ -6317,16 +6539,38 @@ expand_expr (exp, target, tmode, modifier)
                                     TREE_OPERAND (TREE_OPERAND (exp, 2), 0), 0))
          singleton = TREE_OPERAND (exp, 1), unary_op = TREE_OPERAND (exp, 2);
 
-       /* If we had X ? A + 1 : A and we can do the test of X as a store-flag
-          operation, do this as A + (X != 0).  Similarly for other simple
-          binary operators.  */
-       if (temp && singleton && binary_op
-           && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
-           && (TREE_CODE (binary_op) == PLUS_EXPR
-               || TREE_CODE (binary_op) == MINUS_EXPR
-               || TREE_CODE (binary_op) == BIT_IOR_EXPR
+       /* If we are not to produce a result, we have no target.  Otherwise,
+          if a target was specified use it; it will not be used as an
+          intermediate target unless it is safe.  If no target, use a 
+          temporary.  */
+
+       if (ignore)
+         temp = 0;
+       else if (original_target
+                && (safe_from_p (original_target, TREE_OPERAND (exp, 0))
+                    || (singleton && GET_CODE (original_target) == REG
+                        && REGNO (original_target) >= FIRST_PSEUDO_REGISTER
+                        && original_target == var_rtx (singleton)))
+                && GET_MODE (original_target) == mode
+                && ! (GET_CODE (original_target) == MEM
+                      && MEM_VOLATILE_P (original_target)))
+         temp = original_target;
+       else if (TREE_ADDRESSABLE (type))
+         abort ();
+       else
+         temp = assign_temp (type, 0, 0, 1);
+
+       /* If we had X ? A + C : A, with C a constant power of 2, and we can
+          do the test of X as a store-flag operation, do this as
+          A + ((X != 0) << log C).  Similarly for other simple binary
+          operators.  Only do for C == 1 if BRANCH_COST is low.  */
+       if (temp && singleton && binary_op
+           && (TREE_CODE (binary_op) == PLUS_EXPR
+               || TREE_CODE (binary_op) == MINUS_EXPR
+               || TREE_CODE (binary_op) == BIT_IOR_EXPR
                || TREE_CODE (binary_op) == BIT_XOR_EXPR)
-           && integer_onep (TREE_OPERAND (binary_op, 1))
+           && (BRANCH_COST >= 3 ? integer_pow2p (TREE_OPERAND (binary_op, 1))
+               : integer_onep (TREE_OPERAND (binary_op, 1)))
            && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
          {
            rtx result;
@@ -6351,6 +6595,15 @@ expand_expr (exp, target, tmode, modifier)
                                     ? temp : NULL_RTX),
                                    mode, BRANCH_COST <= 1);
 
+           if (result != 0 && ! integer_onep (TREE_OPERAND (binary_op, 1)))
+             result = expand_shift (LSHIFT_EXPR, mode, result,
+                                    build_int_2 (tree_log2
+                                                 (TREE_OPERAND
+                                                  (binary_op, 1)),
+                                                 0),
+                                    (safe_from_p (temp, singleton)
+                                     ? temp : NULL_RTX), 0);
+
            if (result)
              {
                op1 = expand_expr (singleton, NULL_RTX, VOIDmode, 0);
@@ -6366,7 +6619,6 @@ expand_expr (exp, target, tmode, modifier)
        NO_DEFER_POP;
        op0 = gen_label_rtx ();
 
-       flag = gen_reg_rtx (word_mode);
        if (singleton && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0)))
          {
            if (temp != 0)
@@ -6385,14 +6637,12 @@ expand_expr (exp, target, tmode, modifier)
            else
              expand_expr (singleton,
                           ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
-           dest_left_flag = get_last_insn ();
            if (singleton == TREE_OPERAND (exp, 1))
              jumpif (TREE_OPERAND (exp, 0), op0);
            else
              jumpifnot (TREE_OPERAND (exp, 0), op0);
 
-           /* Allows cleanups up to here. */
-           old_cleanups = cleanups_this_call;
+           start_cleanup_deferal ();
            if (binary_op && temp == 0)
              /* Just touch the other operand.  */
              expand_expr (TREE_OPERAND (binary_op, 1),
@@ -6407,43 +6657,7 @@ expand_expr (exp, target, tmode, modifier)
                                  make_tree (type, temp)),
                          temp, 0);
            op1 = op0;
-           dest_right_flag = get_last_insn ();
          }
-#if 0
-       /* This is now done in jump.c and is better done there because it
-          produces shorter register lifetimes.  */
-          
-       /* Check for both possibilities either constants or variables
-          in registers (but not the same as the target!).  If so, can
-          save branches by assigning one, branching, and assigning the
-          other.  */
-       else if (temp && GET_MODE (temp) != BLKmode
-                && (TREE_CONSTANT (TREE_OPERAND (exp, 1))
-                    || ((TREE_CODE (TREE_OPERAND (exp, 1)) == PARM_DECL
-                         || TREE_CODE (TREE_OPERAND (exp, 1)) == VAR_DECL)
-                        && DECL_RTL (TREE_OPERAND (exp, 1))
-                        && GET_CODE (DECL_RTL (TREE_OPERAND (exp, 1))) == REG
-                        && DECL_RTL (TREE_OPERAND (exp, 1)) != temp))
-                && (TREE_CONSTANT (TREE_OPERAND (exp, 2))
-                    || ((TREE_CODE (TREE_OPERAND (exp, 2)) == PARM_DECL
-                         || TREE_CODE (TREE_OPERAND (exp, 2)) == VAR_DECL)
-                        && DECL_RTL (TREE_OPERAND (exp, 2))
-                        && GET_CODE (DECL_RTL (TREE_OPERAND (exp, 2))) == REG
-                        && DECL_RTL (TREE_OPERAND (exp, 2)) != temp)))
-         {
-           if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
-             temp = gen_reg_rtx (mode);
-           store_expr (TREE_OPERAND (exp, 2), temp, 0);
-           dest_left_flag = get_last_insn ();
-           jumpifnot (TREE_OPERAND (exp, 0), op0);
-
-           /* Allows cleanups up to here. */
-           old_cleanups = cleanups_this_call;
-           store_expr (TREE_OPERAND (exp, 1), temp, 0);
-           op1 = op0;
-           dest_right_flag = get_last_insn ();
-         }
-#endif
        /* Check for A op 0 ? A : FOO and A op 0 ? FOO : A where OP is any
           comparison operator.  If we have one of these cases, set the
           output to A, branch on A (cse will merge these two references),
@@ -6459,14 +6673,11 @@ expand_expr (exp, target, tmode, modifier)
            if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
              temp = gen_reg_rtx (mode);
            store_expr (TREE_OPERAND (exp, 1), temp, 0);
-           dest_left_flag = get_last_insn ();
            jumpif (TREE_OPERAND (exp, 0), op0);
 
-           /* Allows cleanups up to here. */
-           old_cleanups = cleanups_this_call;
+           start_cleanup_deferal ();
            store_expr (TREE_OPERAND (exp, 2), temp, 0);
            op1 = op0;
-           dest_right_flag = get_last_insn ();
          }
        else if (temp
                 && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<'
@@ -6479,108 +6690,47 @@ expand_expr (exp, target, tmode, modifier)
            if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
              temp = gen_reg_rtx (mode);
            store_expr (TREE_OPERAND (exp, 2), temp, 0);
-           dest_left_flag = get_last_insn ();
            jumpifnot (TREE_OPERAND (exp, 0), op0);
 
-           /* Allows cleanups up to here. */
-           old_cleanups = cleanups_this_call;
+           start_cleanup_deferal ();
            store_expr (TREE_OPERAND (exp, 1), temp, 0);
            op1 = op0;
-           dest_right_flag = get_last_insn ();
          }
        else
          {
            op1 = gen_label_rtx ();
            jumpifnot (TREE_OPERAND (exp, 0), op0);
 
-           /* Allows cleanups up to here. */
-           old_cleanups = cleanups_this_call;
+           start_cleanup_deferal ();
            if (temp != 0)
              store_expr (TREE_OPERAND (exp, 1), temp, 0);
            else
              expand_expr (TREE_OPERAND (exp, 1),
                           ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
-           dest_left_flag = get_last_insn ();
-
-           /* Handle conditional cleanups, if any. */
-           left_cleanups = defer_cleanups_to (old_cleanups);
-
+           end_cleanup_deferal ();
            emit_queue ();
            emit_jump_insn (gen_jump (op1));
            emit_barrier ();
            emit_label (op0);
+           start_cleanup_deferal ();
            if (temp != 0)
              store_expr (TREE_OPERAND (exp, 2), temp, 0);
            else
              expand_expr (TREE_OPERAND (exp, 2),
                           ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
-           dest_right_flag = get_last_insn ();
          }
 
-       /* Handle conditional cleanups, if any. */
-       right_cleanups = defer_cleanups_to (old_cleanups);
+       end_cleanup_deferal ();
 
        emit_queue ();
        emit_label (op1);
        OK_DEFER_POP;
 
-       /* Add back in, any conditional cleanups. */
-       if (left_cleanups || right_cleanups)
-         {
-           tree new_cleanups;
-           tree cond;
-           rtx last;
-
-           /* Now that we know that a flag is needed, go back and add in the
-              setting of the flag. */
-
-           /* Do the left side flag. */
-           last = get_last_insn ();
-           /* Flag left cleanups as needed. */
-           emit_move_insn (flag, const1_rtx);
-           /* ??? deprecated, use sequences instead.  */
-           reorder_insns (NEXT_INSN (last), get_last_insn (), dest_left_flag);
-
-           /* Do the right side flag. */
-           last = get_last_insn ();
-           /* Flag left cleanups as needed. */
-           emit_move_insn (flag, const0_rtx);
-           /* ??? deprecated, use sequences instead.  */
-           reorder_insns (NEXT_INSN (last), get_last_insn (), dest_right_flag);
-
-           /* All cleanups must be on the function_obstack.  */
-           push_obstacks_nochange ();
-           resume_temporary_allocation ();
-
-           /* convert flag, which is an rtx, into a tree. */
-           cond = make_node (RTL_EXPR);
-           TREE_TYPE (cond) = integer_type_node;
-           RTL_EXPR_RTL (cond) = flag;
-           RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
-           cond = save_expr (cond);
-
-           if (! left_cleanups)
-             left_cleanups = integer_zero_node;
-           if (! right_cleanups)
-             right_cleanups = integer_zero_node;
-           new_cleanups = build (COND_EXPR, void_type_node,
-                                 truthvalue_conversion (cond),
-                                 left_cleanups, right_cleanups);
-           new_cleanups = fold (new_cleanups);
-
-           pop_obstacks ();
-
-           /* Now add in the conditionalized cleanups. */
-           cleanups_this_call
-             = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
-           (*interim_eh_hook) (NULL_TREE);
-         }
        return temp;
       }
 
     case TARGET_EXPR:
       {
-       int need_exception_region = 0;
        /* Something needs to be initialized, but we didn't know
           where that thing was when building the tree.  For example,
           it could be the return value of a function, or a parameter
@@ -6591,6 +6741,7 @@ expand_expr (exp, target, tmode, modifier)
           or copied into our original target.  */
 
        tree slot = TREE_OPERAND (exp, 0);
+       tree cleanups = NULL_TREE;
        tree exp1;
        rtx temp;
 
@@ -6626,13 +6777,7 @@ expand_expr (exp, target, tmode, modifier)
 
                if (TREE_OPERAND (exp, 2) == 0)
                  TREE_OPERAND (exp, 2) = maybe_build_cleanup (slot);
-               if (TREE_OPERAND (exp, 2))
-                 {
-                   cleanups_this_call = tree_cons (NULL_TREE,
-                                                   TREE_OPERAND (exp, 2),
-                                                   cleanups_this_call);
-                   need_exception_region = 1;
-                 }
+               cleanups = TREE_OPERAND (exp, 2);
              }
          }
        else
@@ -6657,16 +6802,15 @@ expand_expr (exp, target, tmode, modifier)
            DECL_RTL (slot) = target;
          }
 
-       exp1 = TREE_OPERAND (exp, 1);
+       exp1 = TREE_OPERAND (exp, 3) = TREE_OPERAND (exp, 1);
        /* Mark it as expanded.  */
        TREE_OPERAND (exp, 1) = NULL_TREE;
 
-       temp = expand_expr (exp1, target, tmode, modifier);
+       store_expr (exp1, target, 0);
 
-       if (need_exception_region)
-         (*interim_eh_hook) (NULL_TREE);
+       expand_decl_cleanup (NULL_TREE, cleanups);
        
-       return temp;
+       return target;
       }
 
     case INIT_EXPR:
@@ -6759,21 +6903,22 @@ expand_expr (exp, target, tmode, modifier)
 
     case PREINCREMENT_EXPR:
     case PREDECREMENT_EXPR:
-      return expand_increment (exp, 0);
+      return expand_increment (exp, 0, ignore);
 
     case POSTINCREMENT_EXPR:
     case POSTDECREMENT_EXPR:
       /* Faster to treat as pre-increment if result is not used.  */
-      return expand_increment (exp, ! ignore);
+      return expand_increment (exp, ! ignore, ignore);
 
     case ADDR_EXPR:
       /* If nonzero, TEMP will be set to the address of something that might
-        be a MEM corresponding to a stack slot. */
+        be a MEM corresponding to a stack slot.  */
       temp = 0;
 
       /* Are we taking the address of a nested function?  */
       if (TREE_CODE (TREE_OPERAND (exp, 0)) == FUNCTION_DECL
-         && decl_function_context (TREE_OPERAND (exp, 0)) != 0)
+         && decl_function_context (TREE_OPERAND (exp, 0)) != 0
+         && ! DECL_NO_STATIC_CHAIN (TREE_OPERAND (exp, 0)))
        {
          op0 = trampoline_address (TREE_OPERAND (exp, 0));
          op0 = force_operand (op0, target);
@@ -6817,7 +6962,7 @@ expand_expr (exp, target, tmode, modifier)
                   || GET_CODE (op0) == CONCAT)
            {
              /* If this object is in a register, it must be not
-                be BLKmode. */
+                be BLKmode.  */
              tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
              rtx memloc = assign_temp (inner_type, 1, 1, 1);
 
@@ -6946,6 +7091,33 @@ expand_expr (exp, target, tmode, modifier)
        return target;
       }
 
+    case TRY_CATCH_EXPR:
+      {
+       tree handler = TREE_OPERAND (exp, 1);
+
+       expand_eh_region_start ();
+
+       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
+
+       expand_eh_region_end (handler);
+
+       return op0;
+      }
+
+    case POPDCC_EXPR:
+      {
+       rtx dcc = get_dynamic_cleanup_chain ();
+       emit_move_insn (dcc, validize_mem (gen_rtx (MEM, Pmode, dcc)));
+       return const0_rtx;
+      }
+
+    case POPDHC_EXPR:
+      {
+       rtx dhc = get_dynamic_handler_chain ();
+       emit_move_insn (dhc, validize_mem (gen_rtx (MEM, Pmode, dhc)));
+       return const0_rtx;
+      }
+
     case ERROR_MARK:
       op0 = CONST0_RTX (tmode);
       if (op0 != 0)
@@ -6973,7 +7145,8 @@ expand_expr (exp, target, tmode, modifier)
 }
 
 
-/* Emit bytecode to evaluate the given expression EXP to the stack. */
+/* Emit bytecode to evaluate the given expression EXP to the stack.  */
+
 void
 bc_expand_expr (exp)
     tree exp;
@@ -7088,7 +7261,7 @@ bc_expand_expr (exp)
        
        /* Allocate a location for the return value and push its
           address on the evaluation stack.  Also make an entry
-          at the front of the calldesc for the return value type. */
+          at the front of the calldesc for the return value type.  */
        
        type = TREE_TYPE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))));
        retval = bc_allocate_local (int_size_in_bytes (type), TYPE_ALIGN (type));
@@ -7109,7 +7282,7 @@ bc_expand_expr (exp)
        r = output_constant_def (calldesc);
        bc_load_externaddr (r);
        
-       /* Push the address of the function to be called. */
+       /* Push the address of the function to be called.  */
        bc_expand_expr (TREE_OPERAND (exp, 0));
        
        /* Call the function, popping its address and the calldesc vector
@@ -7662,8 +7835,8 @@ c_strlen (src)
 rtx
 expand_builtin_return_addr (fndecl_code, count, tem)
      enum built_in_function fndecl_code;
-     rtx tem;
      int count;
+     rtx tem;
 {
   int i;
 
@@ -7710,6 +7883,174 @@ expand_builtin_return_addr (fndecl_code, count, tem)
 #endif
   return tem;
 }
+
+/* __builtin_setjmp is passed a pointer to an array of five words (not
+   all will be used on all machines).  It operates similarly to the C
+   library function of the same name, but is more efficient.  Much of
+   the code below (and for longjmp) is copied from the handling of
+   non-local gotos.
+
+   NOTE: This is intended for use by GNAT and the exception handling
+   scheme in the compiler and will only work in the method used by
+   them.  */
+
+rtx
+expand_builtin_setjmp (buf_addr, target)
+     rtx buf_addr;
+     rtx target;
+{
+  rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
+  enum machine_mode sa_mode = Pmode, value_mode;
+  rtx stack_save;
+  int old_inhibit_defer_pop = inhibit_defer_pop;
+  int return_pops
+    =  RETURN_POPS_ARGS (get_identifier ("__dummy"),
+                        build_function_type (void_type_node, NULL_TREE),
+                        0);
+  rtx next_arg_reg;
+  CUMULATIVE_ARGS args_so_far;
+  rtx op0;
+  int i;
+
+  value_mode = TYPE_MODE (integer_type_node);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+  buf_addr = convert_memory_address (Pmode, buf_addr);
+#endif
+
+  buf_addr = force_reg (Pmode, buf_addr);
+
+  if (target == 0 || GET_CODE (target) != REG
+      || REGNO (target) < FIRST_PSEUDO_REGISTER)
+    target = gen_reg_rtx (value_mode);
+
+  emit_queue ();
+
+  CONST_CALL_P (emit_note (NULL_PTR, NOTE_INSN_SETJMP)) = 1;
+  current_function_calls_setjmp = 1;
+
+  /* We store the frame pointer and the address of lab1 in the buffer
+     and use the rest of it for the stack save area, which is
+     machine-dependent.  */
+  emit_move_insn (gen_rtx (MEM, Pmode, buf_addr),
+                 virtual_stack_vars_rtx);
+  emit_move_insn
+    (validize_mem (gen_rtx (MEM, Pmode,
+                           plus_constant (buf_addr,
+                                          GET_MODE_SIZE (Pmode)))),
+     gen_rtx (LABEL_REF, Pmode, lab1));
+
+#ifdef HAVE_save_stack_nonlocal
+  if (HAVE_save_stack_nonlocal)
+    sa_mode = insn_operand_mode[(int) CODE_FOR_save_stack_nonlocal][0];
+#endif
+
+  stack_save = gen_rtx (MEM, sa_mode,
+                       plus_constant (buf_addr,
+                                      2 * GET_MODE_SIZE (Pmode)));
+  emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
+
+#ifdef HAVE_setjmp
+  if (HAVE_setjmp)
+    emit_insn (gen_setjmp ());
+#endif
+
+  /* Set TARGET to zero and branch around the other case.  */
+  emit_move_insn (target, const0_rtx);
+  emit_jump_insn (gen_jump (lab2));
+  emit_barrier ();
+  emit_label (lab1);
+
+  /* Note that setjmp clobbers FP when we get here, so we have to make
+     sure it's marked as used by this function.  */
+  emit_insn (gen_rtx (USE, VOIDmode, hard_frame_pointer_rtx));
+
+  /* Mark the static chain as clobbered here so life information
+     doesn't get messed up for it.  */
+  emit_insn (gen_rtx (CLOBBER, VOIDmode, static_chain_rtx));
+
+  /* Now put in the code to restore the frame pointer, and argument
+     pointer, if needed.  The code below is from expand_end_bindings
+     in stmt.c; see detailed documentation there.  */
+#ifdef HAVE_nonlocal_goto
+  if (! HAVE_nonlocal_goto)
+#endif
+    emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
+
+  /* Do we need to do something like:
+     
+     current_function_has_nonlocal_label = 1;
+
+     here?  It seems like we might have to, or some subset of that
+     functionality, but I am unsure.  (mrs) */
+
+#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+  if (fixed_regs[ARG_POINTER_REGNUM])
+    {
+#ifdef ELIMINABLE_REGS
+      static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
+
+      for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
+       if (elim_regs[i].from == ARG_POINTER_REGNUM
+           && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
+         break;
+
+      if (i == sizeof elim_regs / sizeof elim_regs [0])
+#endif
+       {
+         /* Now restore our arg pointer from the address at which it
+            was saved in our stack frame.
+            If there hasn't be space allocated for it yet, make
+            some now.  */
+         if (arg_pointer_save_area == 0)
+           arg_pointer_save_area
+             = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
+         emit_move_insn (virtual_incoming_args_rtx,
+                         copy_to_reg (arg_pointer_save_area));
+       }
+    }
+#endif
+
+#ifdef HAVE_nonlocal_goto_receiver
+  if (HAVE_nonlocal_goto_receiver)
+    emit_insn (gen_nonlocal_goto_receiver ());
+#endif
+  /* The static chain pointer contains the address of dummy function.
+     We need to call it here to handle some PIC cases of restoring a
+     global pointer.  Then return 1.  */
+  op0 = copy_to_mode_reg (Pmode, static_chain_rtx);
+
+  /* We can't actually call emit_library_call here, so do everything
+     it does, which isn't much for a libfunc with no args.  */
+  op0 = memory_address (FUNCTION_MODE, op0);
+
+  INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE,
+                       gen_rtx (SYMBOL_REF, Pmode, "__dummy"), 1);
+  next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1);
+
+#ifndef ACCUMULATE_OUTGOING_ARGS
+#ifdef HAVE_call_pop
+  if (HAVE_call_pop)
+    emit_call_insn (gen_call_pop (gen_rtx (MEM, FUNCTION_MODE, op0),
+                                 const0_rtx, next_arg_reg,
+                                 GEN_INT (return_pops)));
+  else
+#endif
+#endif
+
+#ifdef HAVE_call
+    if (HAVE_call)
+      emit_call_insn (gen_call (gen_rtx (MEM, FUNCTION_MODE, op0),
+                               const0_rtx, next_arg_reg, const0_rtx));
+    else
+#endif
+      abort ();
+
+  emit_move_insn (target, const1_rtx);
+  emit_label (lab2);
+  return target;
+}
+
 \f
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
@@ -7745,7 +8086,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
 
     case BUILT_IN_SIN:
     case BUILT_IN_COS:
-      /* Treat these like sqrt, but only if the user asks for them. */
+      /* Treat these like sqrt, but only if the user asks for them.  */
       if (! flag_fast_math)
        break;
     case BUILT_IN_FSQRT:
@@ -7831,7 +8172,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
          }
 #else
          /* We can't set errno=EDOM directly; let the library call do it.
-            Pop the arguments right away in case the call gets deleted. */
+            Pop the arguments right away in case the call gets deleted.  */
          NO_DEFER_POP;
          expand_call (exp, target, 0);
          OK_DEFER_POP;
@@ -7840,7 +8181,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
          emit_label (lab1);
        }
 
-      /* Output the entire sequence. */
+      /* Output the entire sequence.  */
       insns = get_insns ();
       end_sequence ();
       emit_insns (insns);
@@ -8142,14 +8483,13 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       if (arglist == 0)
        /* Warning about missing arg was already issued.  */
        return const0_rtx;
-      else if (TREE_CODE (TREE_VALUE (arglist)) != INTEGER_CST)
-       {
-         error ("invalid arg to `__builtin_return_address'");
-         return const0_rtx;
-       }
-      else if (tree_int_cst_sgn (TREE_VALUE (arglist)) < 0)
+      else if (TREE_CODE (TREE_VALUE (arglist)) != INTEGER_CST
+              || tree_int_cst_sgn (TREE_VALUE (arglist)) < 0)
        {
-         error ("invalid arg to `__builtin_return_address'");
+         if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
+           error ("invalid arg to `__builtin_frame_address'");
+         else
+           error ("invalid arg to `__builtin_return_address'");
          return const0_rtx;
        }
       else
@@ -8220,15 +8560,15 @@ expand_builtin (exp, target, subtarget, mode, ignore)
          enum machine_mode insn_mode = value_mode, char_mode;
          enum insn_code icode;
 
-         /* If the length is known, just return it. */
+         /* If the length is known, just return it.  */
          if (len != 0)
            return expand_expr (len, target, mode, 0);
 
-         /* If SRC is not a pointer type, don't do this operation inline. */
+         /* If SRC is not a pointer type, don't do this operation inline.  */
          if (align == 0)
            break;
 
-         /* Call a function if we can't compute strlen in the right mode. */
+         /* Call a function if we can't compute strlen in the right mode.  */
 
          while (insn_mode != VOIDmode)
            {
@@ -8366,6 +8706,58 @@ expand_builtin (exp, target, subtarget, mode, ignore)
          return force_operand (dest_rtx, NULL_RTX);
        }
 
+    case BUILT_IN_MEMSET:
+      /* If not optimizing, call the library function.  */
+      if (!optimize && ! CALLED_AS_BUILT_IN (fndecl))
+       break;
+
+      if (arglist == 0
+         /* Arg could be non-pointer if user redeclared this fcn wrong.  */
+         || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
+         || TREE_CHAIN (arglist) == 0
+         || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
+             != INTEGER_TYPE)
+         || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
+         || (INTEGER_CST
+             != (TREE_CODE (TREE_TYPE
+                            (TREE_VALUE
+                             (TREE_CHAIN (TREE_CHAIN (arglist))))))))
+       break;
+      else
+       {
+         tree dest = TREE_VALUE (arglist);
+         tree val = TREE_VALUE (TREE_CHAIN (arglist));
+         tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+         tree type;
+
+         int dest_align
+           = get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
+         rtx dest_rtx, dest_mem;
+
+         /* If DEST is not a pointer type, don't do this 
+            operation in-line.  */
+         if (dest_align == 0)
+           break;
+
+         /* If VAL is not 0, don't do this operation in-line. */
+         if (expand_expr (val, NULL_RTX, VOIDmode, 0) != const0_rtx)
+           break;
+
+         dest_rtx = expand_expr (dest, NULL_RTX, ptr_mode, EXPAND_SUM);
+         dest_mem = gen_rtx (MEM, BLKmode,
+                             memory_address (BLKmode, dest_rtx));
+         /* There could be a void* cast on top of the object.  */
+         while (TREE_CODE (dest) == NOP_EXPR)
+           dest = TREE_OPERAND (dest, 0);
+         type = TREE_TYPE (TREE_TYPE (dest));
+         MEM_IN_STRUCT_P (dest_mem) = AGGREGATE_TYPE_P (type);
+
+         clear_storage (dest_mem, expand_expr (len, NULL_RTX, VOIDmode, 0),
+                           dest_align);
+
+         return force_operand (dest_rtx, NULL_RTX);
+       }
+
 /* These comparison functions need an instruction that returns an actual
    index.  An ordinary compare that just sets the condition codes
    is not enough.  */
@@ -8496,112 +8888,19 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       break;
 #endif
 
-      /* __builtin_setjmp is passed a pointer to an array of five words
-        (not all will be used on all machines).  It operates similarly to
-        the C library function of the same name, but is more efficient.
-        Much of the code below (and for longjmp) is copied from the handling
-        of non-local gotos.
-
-        NOTE: This is intended for use by GNAT and will only work in
-        the method used by it.  This code will likely NOT survive to 
-        the GCC 2.8.0 release.  */
     case BUILT_IN_SETJMP:
       if (arglist == 0
          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
        break;
 
       {
-       rtx buf_addr
-         = force_reg (Pmode, expand_expr (TREE_VALUE (arglist), subtarget,
-                                          VOIDmode, 0));
-       rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
-       enum machine_mode sa_mode = Pmode;
-       rtx stack_save;
-
-       if (target == 0 || GET_CODE (target) != REG
-           || REGNO (target) < FIRST_PSEUDO_REGISTER)
-         target = gen_reg_rtx (value_mode);
-
-       emit_queue ();
-
-       emit_note (NULL_PTR, NOTE_INSN_SETJMP);
-       current_function_calls_setjmp = 1;
-
-       /* We store the frame pointer and the address of lab1 in the buffer
-          and use the rest of it for the stack save area, which is
-          machine-dependent.  */
-       emit_move_insn (gen_rtx (MEM, Pmode, buf_addr),
-                       virtual_stack_vars_rtx);
-       emit_move_insn
-         (validize_mem (gen_rtx (MEM, Pmode,
-                                 plus_constant (buf_addr,
-                                                GET_MODE_SIZE (Pmode)))),
-          gen_rtx (LABEL_REF, Pmode, lab1));
-
-#ifdef HAVE_save_stack_nonlocal
-       if (HAVE_save_stack_nonlocal)
-         sa_mode = insn_operand_mode[(int) CODE_FOR_save_stack_nonlocal][0];
-#endif
-
-       stack_save = gen_rtx (MEM, sa_mode,
-                             plus_constant (buf_addr,
-                                            2 * GET_MODE_SIZE (Pmode)));
-       emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
-
-       /* Set TARGET to zero and branch around the other case.  */
-       emit_move_insn (target, const0_rtx);
-       emit_jump_insn (gen_jump (lab2));
-       emit_barrier ();
-       emit_label (lab1);
-
-       /* Now put in the code to restore the frame pointer, and argument
-          pointer, if needed.  The code below is from expand_end_bindings
-          in stmt.c; see detailed documentation there.  */
-#ifdef HAVE_nonlocal_goto
-       if (! HAVE_nonlocal_goto)
-#endif
-         emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
-
-#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
-       if (fixed_regs[ARG_POINTER_REGNUM])
-         {
-#ifdef ELIMINABLE_REGS
-           static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
-           int i;
-
-           for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
-             if (elim_regs[i].from == ARG_POINTER_REGNUM
-                 && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
-               break;
-
-           if (i == sizeof elim_regs / sizeof elim_regs [0])
-#endif
-             {
-               /* Now restore our arg pointer from the address at which it
-                  was saved in our stack frame.
-                  If there hasn't be space allocated for it yet, make
-                  some now.  */
-               if (arg_pointer_save_area == 0)
-                 arg_pointer_save_area
-                   = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
-               emit_move_insn (virtual_incoming_args_rtx,
-                               copy_to_reg (arg_pointer_save_area));
-             }
-         }
-#endif
-
-       /* The result to return is in the static chain pointer.  */
-       if (GET_MODE (static_chain_rtx) == GET_MODE (target))
-         emit_move_insn (target, static_chain_rtx);
-       else
-         convert_move (target, static_chain_rtx, 0);
-
-       emit_label (lab2);
-       return target;
+       rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
+                                   VOIDmode, 0);
+       return expand_builtin_setjmp (buf_addr, target);
       }
 
       /* __builtin_longjmp is passed a pointer to an array of five words
-        and a value to return.  It's similar to the C library longjmp
+        and a value, which is a dummy.  It's similar to the C library longjmp
         function but works with __builtin_setjmp above.  */
     case BUILT_IN_LONGJMP:
       if (arglist == 0 || TREE_CHAIN (arglist) == 0
@@ -8609,9 +8908,22 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        break;
 
       {
+       tree dummy_id = get_identifier ("__dummy");
+       tree dummy_type = build_function_type (void_type_node, NULL_TREE);
+       tree dummy_decl = build_decl (FUNCTION_DECL, dummy_id, dummy_type); 
+#ifdef POINTERS_EXTEND_UNSIGNED
+       rtx buf_addr
+         = force_reg (Pmode,
+                      convert_memory_address
+                      (Pmode,
+                       expand_expr (TREE_VALUE (arglist),
+                                    NULL_RTX, VOIDmode, 0)));
+#else
        rtx buf_addr
-         = force_reg (Pmode, expand_expr (TREE_VALUE (arglist), NULL_RTX,
+         = force_reg (Pmode, expand_expr (TREE_VALUE (arglist),
+                                          NULL_RTX,
                                           VOIDmode, 0));
+#endif
        rtx fp = gen_rtx (MEM, Pmode, buf_addr);
        rtx lab = gen_rtx (MEM, Pmode,
                           plus_constant (buf_addr, GET_MODE_SIZE (Pmode)));
@@ -8626,26 +8938,37 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        rtx stack = gen_rtx (MEM, sa_mode,
                             plus_constant (buf_addr,
                                            2 * GET_MODE_SIZE (Pmode)));
-       rtx value = expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), NULL_RTX,
-                                VOIDmode, 0);
+
+       DECL_EXTERNAL (dummy_decl) = 1;
+       TREE_PUBLIC (dummy_decl) = 1;
+       make_decl_rtl (dummy_decl, NULL_PTR, 1);
+
+       /* Expand the second expression just for side-effects.  */
+       expand_expr (TREE_VALUE (TREE_CHAIN (arglist)),
+                    const0_rtx, VOIDmode, 0);
+
+       assemble_external (dummy_decl);
 
        /* Pick up FP, label, and SP from the block and jump.  This code is
           from expand_goto in stmt.c; see there for detailed comments.  */
 #if HAVE_nonlocal_goto
        if (HAVE_nonlocal_goto)
-         emit_insn (gen_nonlocal_goto (fp, lab, stack, value));
+         emit_insn (gen_nonlocal_goto (fp, lab, stack,
+                                       XEXP (DECL_RTL (dummy_decl), 0)));
       else
 #endif
        {
+         lab = copy_to_reg (lab);
          emit_move_insn (hard_frame_pointer_rtx, fp);
          emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
 
-         /* Put in the static chain register the return value.  */
-         emit_move_insn (static_chain_rtx, value);
+         /* Put in the static chain register the address of the dummy
+            function.  */
+         emit_move_insn (static_chain_rtx, XEXP (DECL_RTL (dummy_decl), 0));
          emit_insn (gen_rtx (USE, VOIDmode, hard_frame_pointer_rtx));
          emit_insn (gen_rtx (USE, VOIDmode, stack_pointer_rtx));
          emit_insn (gen_rtx (USE, VOIDmode, static_chain_rtx));
-         emit_indirect_jump (copy_to_reg (lab));
+         emit_indirect_jump (lab);
        }
 
        return const0_rtx;
@@ -8681,12 +9004,12 @@ static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER];
 /* For each register that may be used for calling a function, this
    gives the offset of that register into the block returned by
    __builtin_apply_args.  0 indicates that the register is not
-   used for calling a function. */
+   used for calling a function.  */
 static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER];
 
 /* Return the offset of register REGNO into the block returned by 
    __builtin_apply_args.  This is not declared static, since it is
-   needed in objc-act.c. */
+   needed in objc-act.c.  */
 
 int 
 apply_args_register_offset (regno)
@@ -8695,7 +9018,7 @@ apply_args_register_offset (regno)
   apply_args_size ();
 
   /* Arguments are always put in outgoing registers (in the argument
-     block) if such make sense. */
+     block) if such make sense.  */
 #ifdef OUTGOING_REGNO
   regno = OUTGOING_REGNO(regno);
 #endif
@@ -9145,9 +9468,9 @@ expand_builtin_return (result)
    POST is 1 for postinc/decrements and 0 for preinc/decrements.  */
 
 static rtx
-expand_increment (exp, post)
+expand_increment (exp, post, ignore)
      register tree exp;
-     int post;
+     int post, ignore;
 {
   register rtx op0, op1;
   register rtx temp, value;
@@ -9278,7 +9601,7 @@ expand_increment (exp, post)
          incremented = TREE_OPERAND (incremented, 0);
        }
 
-      temp = expand_assignment (incremented, newexp, ! post, 0);
+      temp = expand_assignment (incremented, newexp, ! post && ! ignore , 0);
       return post ? op0 : temp;
     }
 
@@ -9306,6 +9629,22 @@ expand_increment (exp, post)
 
          return enqueue_insn (op0, GEN_FCN (icode) (op0, op0, op1));
        }
+      if (icode != (int) CODE_FOR_nothing && GET_CODE (op0) == MEM)
+       {
+         rtx addr = force_reg (Pmode, XEXP (op0, 0));
+         rtx temp, result;
+
+         op0 = change_address (op0, VOIDmode, addr);
+         temp = force_reg (GET_MODE (op0), op0);
+         if (! (*insn_operand_predicate[icode][2]) (op1, mode))
+           op1 = force_reg (mode, op1);
+
+         /* The increment queue is LIFO, thus we have to `queue'
+            the instructions in reverse order.  */
+         enqueue_insn (op0, gen_move_insn (op0, temp));
+         result = enqueue_insn (temp, GEN_FCN (icode) (temp, temp, op1));
+         return result;
+       }
     }
 
   /* Preincrement, or we can't increment with one simple insn.  */
@@ -9353,16 +9692,17 @@ preexpand_calls (exp)
     {
     case CALL_EXPR:
       /* Do nothing if already expanded.  */
-      if (CALL_EXPR_RTL (exp) != 0)
+      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
+         /* Do nothing to built-in functions.  */
+         || (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
+             && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+                 == FUNCTION_DECL)
+             && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))))
        return;
 
-      /* Do nothing to built-in functions.  */
-      if (TREE_CODE (TREE_OPERAND (exp, 0)) != ADDR_EXPR
-         || TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) != FUNCTION_DECL
-         || ! DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
-         /* Do nothing if the call returns a variable-sized object.  */
-         || TREE_CODE (TYPE_SIZE (TREE_TYPE(exp))) != INTEGER_CST)
-       CALL_EXPR_RTL (exp) = expand_call (exp, NULL_RTX, 0);
+      CALL_EXPR_RTL (exp) = expand_call (exp, NULL_RTX, 0);
       return;
 
     case COMPOUND_EXPR:
@@ -9435,68 +9775,6 @@ do_pending_stack_adjust ()
       pending_stack_adjust = 0;
     }
 }
-
-/* Defer the expansion all cleanups up to OLD_CLEANUPS.
-   Returns the cleanups to be performed.  */
-
-static tree
-defer_cleanups_to (old_cleanups)
-     tree old_cleanups;
-{
-  tree new_cleanups = NULL_TREE;
-  tree cleanups = cleanups_this_call;
-  tree last = NULL_TREE;
-
-  while (cleanups_this_call != old_cleanups)
-    {
-      (*interim_eh_hook) (TREE_VALUE (cleanups_this_call));
-      last = cleanups_this_call;
-      cleanups_this_call = TREE_CHAIN (cleanups_this_call);
-    }      
-
-  if (last)
-    {
-      /* Remove the list from the chain of cleanups.  */
-      TREE_CHAIN (last) = NULL_TREE;
-
-      /* reverse them so that we can build them in the right order.  */
-      cleanups = nreverse (cleanups);
-
-      /* All cleanups must be on the function_obstack.  */
-      push_obstacks_nochange ();
-      resume_temporary_allocation ();
-
-      while (cleanups)
-       {
-         if (new_cleanups)
-           new_cleanups = build (COMPOUND_EXPR, TREE_TYPE (new_cleanups),
-                                 TREE_VALUE (cleanups), new_cleanups);
-         else
-           new_cleanups = TREE_VALUE (cleanups);
-
-         cleanups = TREE_CHAIN (cleanups);
-       }
-
-      pop_obstacks ();
-    }
-
-  return new_cleanups;
-}
-
-/* Expand all cleanups up to OLD_CLEANUPS.
-   Needed here, and also for language-dependent calls.  */
-
-void
-expand_cleanups_to (old_cleanups)
-     tree old_cleanups;
-{
-  while (cleanups_this_call != old_cleanups)
-    {
-      (*interim_eh_hook) (TREE_VALUE (cleanups_this_call));
-      expand_expr (TREE_VALUE (cleanups_this_call), const0_rtx, VOIDmode, 0);
-      cleanups_this_call = TREE_CHAIN (cleanups_this_call);
-    }
-}
 \f
 /* Expand conditional expressions.  */
 
@@ -9641,136 +9919,27 @@ do_jump (exp, if_false_label, if_true_label)
       break;
 
     case TRUTH_ANDIF_EXPR:
-      {
-       rtx seq1, seq2;
-       tree cleanups, old_cleanups;
-
-       if (if_false_label == 0)
-         if_false_label = drop_through_label = gen_label_rtx ();
-       start_sequence ();
-       do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
-       seq1 = get_insns ();
-       end_sequence ();
-
-       old_cleanups = cleanups_this_call;
-       start_sequence ();
-       do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
-       seq2 = get_insns ();
-       end_sequence ();
-
-       cleanups = defer_cleanups_to (old_cleanups);
-       if (cleanups)
-         {
-           rtx flag = gen_reg_rtx (word_mode);
-           tree new_cleanups;
-           tree cond;
-
-           /* Flag cleanups as not needed. */
-           emit_move_insn (flag, const0_rtx);
-           emit_insns (seq1);
-
-           /* Flag cleanups as needed. */
-           emit_move_insn (flag, const1_rtx);
-           emit_insns (seq2);
-
-           /* All cleanups must be on the function_obstack.  */
-           push_obstacks_nochange ();
-           resume_temporary_allocation ();
-
-           /* convert flag, which is an rtx, into a tree. */
-           cond = make_node (RTL_EXPR);
-           TREE_TYPE (cond) = integer_type_node;
-           RTL_EXPR_RTL (cond) = flag;
-           RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
-           cond = save_expr (cond);
-
-           new_cleanups = build (COND_EXPR, void_type_node,
-                                 truthvalue_conversion (cond),
-                                 cleanups, integer_zero_node);
-           new_cleanups = fold (new_cleanups);
-
-           pop_obstacks ();
-
-           /* Now add in the conditionalized cleanups. */
-           cleanups_this_call
-             = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
-           (*interim_eh_hook) (NULL_TREE);
-         }
-       else
-         {
-           emit_insns (seq1);
-           emit_insns (seq2);
-         }
-      }
+      if (if_false_label == 0)
+       if_false_label = drop_through_label = gen_label_rtx ();
+      do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
+      start_cleanup_deferal ();
+      do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
+      end_cleanup_deferal ();
       break;
 
     case TRUTH_ORIF_EXPR:
-      {
-       rtx seq1, seq2;
-       tree cleanups, old_cleanups;
-
-       if (if_true_label == 0)
-         if_true_label = drop_through_label = gen_label_rtx ();
-       start_sequence ();
-       do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
-       seq1 = get_insns ();
-       end_sequence ();
-
-       old_cleanups = cleanups_this_call;
-       start_sequence ();
-       do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
-       seq2 = get_insns ();
-       end_sequence ();
-
-       cleanups = defer_cleanups_to (old_cleanups);
-       if (cleanups)
-         {
-           rtx flag = gen_reg_rtx (word_mode);
-           tree new_cleanups;
-           tree cond;
-
-           /* Flag cleanups as not needed. */
-           emit_move_insn (flag, const0_rtx);
-           emit_insns (seq1);
-
-           /* Flag cleanups as needed. */
-           emit_move_insn (flag, const1_rtx);
-           emit_insns (seq2);
-
-           /* All cleanups must be on the function_obstack.  */
-           push_obstacks_nochange ();
-           resume_temporary_allocation ();
-
-           /* convert flag, which is an rtx, into a tree. */
-           cond = make_node (RTL_EXPR);
-           TREE_TYPE (cond) = integer_type_node;
-           RTL_EXPR_RTL (cond) = flag;
-           RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
-           cond = save_expr (cond);
-
-           new_cleanups = build (COND_EXPR, void_type_node,
-                                 truthvalue_conversion (cond),
-                                 cleanups, integer_zero_node);
-           new_cleanups = fold (new_cleanups);
-
-           pop_obstacks ();
-
-           /* Now add in the conditionalized cleanups. */
-           cleanups_this_call
-             = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
-           (*interim_eh_hook) (NULL_TREE);
-         }
-       else
-         {
-           emit_insns (seq1);
-           emit_insns (seq2);
-         }
-      }
+      if (if_true_label == 0)
+       if_true_label = drop_through_label = gen_label_rtx ();
+      do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
+      start_cleanup_deferal ();
+      do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
+      end_cleanup_deferal ();
       break;
 
     case COMPOUND_EXPR:
       push_temp_slots ();
       expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
+      preserve_temp_slots (NULL_RTX);
       free_temp_slots ();
       pop_temp_slots ();
       emit_queue ();
@@ -9787,11 +9956,13 @@ do_jump (exp, if_false_label, if_true_label)
        tree type;
        tree offset;
        int volatilep = 0;
+       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);
+                            &mode, &unsignedp, &volatilep,
+                            &alignment);
 
        type = type_for_size (bitsize, unsignedp);
        if (! SLOW_BYTE_ACCESS
@@ -9820,7 +9991,10 @@ do_jump (exp, if_false_label, if_true_label)
        {
          register rtx label1 = gen_label_rtx ();
          drop_through_label = gen_label_rtx ();
+
          do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX);
+
+         start_cleanup_deferal ();
          /* Now the THEN-expression.  */
          do_jump (TREE_OPERAND (exp, 1),
                   if_false_label ? if_false_label : drop_through_label,
@@ -9828,10 +10002,12 @@ do_jump (exp, if_false_label, if_true_label)
          /* In case the do_jump just above never jumps.  */
          do_pending_stack_adjust ();
          emit_label (label1);
+
          /* Now the ELSE-expression.  */
          do_jump (TREE_OPERAND (exp, 2),
                   if_false_label ? if_false_label : drop_through_label,
                   if_true_label ? if_true_label : drop_through_label);
+         end_cleanup_deferal ();
        }
       break;
 
@@ -10288,6 +10464,32 @@ compare (exp, signed_code, unsigned_code)
   int unsignedp = TREE_UNSIGNED (type);
   enum rtx_code code = unsignedp ? unsigned_code : signed_code;
 
+#ifdef HAVE_canonicalize_funcptr_for_compare
+  /* If function pointers need to be "canonicalized" before they can
+     be reliably compared, then canonicalize them.  */
+  if (HAVE_canonicalize_funcptr_for_compare
+      && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
+      && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))))
+         == FUNCTION_TYPE))
+    {
+      rtx new_op0 = gen_reg_rtx (mode);
+
+      emit_insn (gen_canonicalize_funcptr_for_compare (new_op0, op0));
+      op0 = new_op0;
+    }
+
+  if (HAVE_canonicalize_funcptr_for_compare
+      && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE
+      && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))))
+         == FUNCTION_TYPE))
+    {
+      rtx new_op1 = gen_reg_rtx (mode);
+
+      emit_insn (gen_canonicalize_funcptr_for_compare (new_op1, op1));
+      op1 = new_op1;
+    }
+#endif
+
   return compare_from_rtx (op0, op1, code, unsignedp, mode,
                           ((mode == BLKmode)
                            ? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX),
@@ -10341,7 +10543,7 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
 #if 0
   /* There's no need to do this now that combine.c can eliminate lots of
      sign extensions.  This can be less efficient in certain cases on other
-     machines. */
+     machines.  */
 
   /* If this is a signed equality comparison, we can do it as an
      unsigned comparison since zero-extension is cheaper than sign
@@ -10422,6 +10624,19 @@ do_store_flag (exp, target, mode, only_cheap)
   if (operand_mode == BLKmode)
     return 0;
 
+  /* We won't bother with store-flag operations involving function pointers
+     when function pointers must be canonicalized before comparisons.  */
+#ifdef HAVE_canonicalize_funcptr_for_compare
+  if (HAVE_canonicalize_funcptr_for_compare
+      && ((TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
+          && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))))
+              == FUNCTION_TYPE))
+         || (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE
+             && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))))
+                 == FUNCTION_TYPE))))
+    return 0;
+#endif
+
   STRIP_NOPS (arg0);
   STRIP_NOPS (arg1);
 
@@ -10487,10 +10702,25 @@ do_store_flag (exp, target, mode, only_cheap)
       && TYPE_PRECISION (type) <= HOST_BITS_PER_WIDE_INT)
     {
       tree inner = TREE_OPERAND (arg0, 0);
-      int bitnum = exact_log2 (INTVAL (expand_expr (TREE_OPERAND (arg0, 1),
-                                                   NULL_RTX, VOIDmode, 0)));
+      HOST_WIDE_INT tem;
+      int bitnum;
       int ops_unsignedp;
 
+      tem = INTVAL (expand_expr (TREE_OPERAND (arg0, 1),
+                                NULL_RTX, VOIDmode, 0));
+      /* In this case, immed_double_const will sign extend the value to make
+        it look the same on the host and target.  We must remove the
+        sign-extension before calling exact_log2, since exact_log2 will
+        fail for negative values.  */
+      if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT
+         && BITS_PER_WORD == GET_MODE_BITSIZE (TYPE_MODE (type)))
+       /* We don't use the obvious constant shift to generate the mask,
+          because that generates compiler warnings when BITS_PER_WORD is
+          greater than or equal to HOST_BITS_PER_WIDE_INT, even though this
+          code is unreachable in that case.  */
+       tem = tem & GET_MODE_MASK (word_mode);
+      bitnum = exact_log2 (tem);
+
       /* If INNER is a right shift of a constant and it plus BITNUM does
         not overflow, adjust BITNUM and INNER.  */
 
@@ -10594,7 +10824,7 @@ do_store_flag (exp, target, mode, only_cheap)
     }
 
   /* If this failed, we have to do this with set/compare/jump/set code.  */
-  if (target == 0 || GET_CODE (target) != REG
+  if (GET_CODE (target) != REG
       || reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
     target = gen_reg_rtx (GET_MODE (target));
 
@@ -10699,7 +10929,7 @@ do_tablejump (index, mode, range, table_label, default_label)
 
 /* Emit a suitable bytecode to load a value from memory, assuming a pointer
    to that value is on the top of the stack. The resulting type is TYPE, and
-   the source declaration is DECL. */
+   the source declaration is DECL.  */
 
 void
 bc_load_memory (type, decl)
@@ -10710,7 +10940,7 @@ bc_load_memory (type, decl)
   
   /* Bit fields are special.  We only know about signed and
      unsigned ints, and enums.  The latter are treated as
-     signed integers. */
+     signed integers.  */
   
   if (DECL_BIT_FIELD (decl))
     if (TREE_CODE (type) == ENUMERAL_TYPE
@@ -10719,7 +10949,7 @@ bc_load_memory (type, decl)
     else
       abort ();
   else
-    /* See corresponding comment in bc_store_memory(). */
+    /* See corresponding comment in bc_store_memory */
     if (TYPE_MODE (type) == BLKmode
        || TYPE_MODE (type) == VOIDmode)
       return;
@@ -10739,7 +10969,7 @@ bc_load_memory (type, decl)
 
 /* Store the contents of the second stack slot to the address in the
    top stack slot.  DECL is the declaration of the destination and is used
-   to determine whether we're dealing with a bitfield. */
+   to determine whether we're dealing with a bitfield.  */
 
 void
 bc_store_memory (type, decl)
@@ -10765,7 +10995,7 @@ bc_store_memory (type, decl)
           structure size in size units (usually bytes).  The two first arguments
           are already on the stack; so we just put the size on level 1.  For some
           other languages, the size may be variable, this is why we don't encode
-          it as a storeBLK literal, but rather treat it as a full-fledged expression. */
+          it as a storeBLK literal, but rather treat it as a full-fledged expression.  */
        
        bc_expand_expr (TYPE_SIZE (type));
        opcode = storeBLK;
@@ -10821,7 +11051,7 @@ bc_allocate_local (size, alignment)
 
 
 /* Allocate variable-sized local array. Variable-sized arrays are
-   actually pointers to the address in memory where they are stored. */
+   actually pointers to the address in memory where they are stored.  */
 
 rtx
 bc_allocate_variable_array (size)
@@ -10844,6 +11074,7 @@ bc_allocate_variable_array (size)
 
 
 /* Push the machine address for the given external variable offset.  */
+
 void
 bc_load_externaddr (externaddr)
      rtx externaddr;
@@ -10858,17 +11089,8 @@ bc_load_externaddr (externaddr)
 }
 
 
-static char *
-bc_strdup (s)
-    char *s;
-{
-  char *new = (char *) xmalloc ((strlen (s) + 1) * sizeof *s);
-  strcpy (new, s);
-  return new;
-}
-
-
 /* Like above, but expects an IDENTIFIER.  */
+
 void
 bc_load_externaddr_id (id, offset)
      tree id;
@@ -10878,7 +11100,7 @@ bc_load_externaddr_id (id, offset)
     abort ();
 
   bc_emit_bytecode (constP);
-  bc_emit_code_labelref (bc_xstrdup (IDENTIFIER_POINTER (id)), offset);
+  bc_emit_code_labelref (xstrdup (IDENTIFIER_POINTER (id)), offset);
 
 #ifdef DEBUG_PRINT_CODE
   fputc ('\n', stderr);
@@ -10887,6 +11109,7 @@ bc_load_externaddr_id (id, offset)
 
 
 /* Push the machine address for the given local variable offset.  */
+
 void
 bc_load_localaddr (localaddr)
      rtx localaddr;
@@ -10896,7 +11119,8 @@ bc_load_localaddr (localaddr)
 
 
 /* Push the machine address for the given parameter offset.
-   NOTE: offset is in bits. */
+   NOTE: offset is in bits.  */
+
 void
 bc_load_parmaddr (parmaddr)
      rtx parmaddr;
@@ -10907,6 +11131,7 @@ bc_load_parmaddr (parmaddr)
 
 
 /* Convert a[i] into *(a + i).  */
+
 tree
 bc_canonicalize_array_ref (exp)
      tree exp;
@@ -10942,7 +11167,7 @@ bc_canonicalize_array_ref (exp)
 /* Load the address of the component referenced by the given
    COMPONENT_REF expression.
 
-   Returns innermost lvalue. */
+   Returns innermost lvalue.  */
 
 tree
 bc_expand_component_address (exp)
@@ -10992,6 +11217,7 @@ bc_expand_component_address (exp)
 
 
 /* Emit code to push two SI constants */
+
 void
 bc_push_offset_and_size (offset, size)
      HOST_WIDE_INT offset, size;
@@ -11005,7 +11231,7 @@ bc_push_offset_and_size (offset, size)
    the stack.  If it's a bit field, we also push offset and size info.
 
    Returns innermost component, which allows us to determine not only
-   its type, but also whether it's a bitfield. */
+   its type, but also whether it's a bitfield.  */
 
 tree
 bc_expand_address (exp)
@@ -11032,7 +11258,7 @@ bc_expand_address (exp)
 
       /* For variable-sized types: retrieve pointer.  Sometimes the
         TYPE_SIZE tree is NULL.  Is this a bug or a feature?  Let's
-        also make sure we have an operand, just in case... */
+        also make sure we have an operand, just in case...  */
 
       if (TREE_OPERAND (exp, 0)
          && TYPE_SIZE (TREE_TYPE (TREE_OPERAND (exp, 0)))
@@ -11119,7 +11345,7 @@ bc_expand_address (exp)
       break;
     }
 
-  /* Most lvalues don't have components. */
+  /* Most lvalues don't have components.  */
   return (exp);
 }
 
@@ -11161,6 +11387,7 @@ bc_runtime_type_code (type)
 
 
 /* Generate constructor label */
+
 char *
 bc_gen_constr_label ()
 {
@@ -11178,7 +11405,7 @@ bc_gen_constr_label ()
    The pointer is put in the pointer table and is retrieved by a constP
    bytecode instruction.  We then loop and store each constructor member in
    the corresponding component.  Finally, we return the original pointer on
-   the stack. */
+   the stack.  */
 
 void
 bc_expand_constructor (constr)
@@ -11191,7 +11418,7 @@ bc_expand_constructor (constr)
   
   /* Literal constructors are handled as constants, whereas
      non-literals are evaluated and stored element by element
-     into the data segment. */
+     into the data segment.  */
   
   /* Allocate space in proper segment and push pointer to space on stack.
    */
@@ -11216,18 +11443,18 @@ bc_expand_constructor (constr)
   
   /* Add reference to pointer table and recall pointer to stack;
      this code is common for both types of constructors: literals
-     and non-literals. */
+     and non-literals.  */
 
   ptroffs = bc_define_pointer (l);
   bc_emit_instruction (constP, ptroffs);
 
-  /* This is all that has to be done if it's a literal. */
+  /* This is all that has to be done if it's a literal.  */
   if (TREE_CONSTANT (constr))
     return;
 
 
   /* At this point, we have the pointer to the structure on top of the stack.
-     Generate sequences of store_memory calls for the constructor. */
+     Generate sequences of store_memory calls for the constructor.  */
   
   /* constructor type is structure */
   if (TREE_CODE (TREE_TYPE (constr)) == RECORD_TYPE)
@@ -11294,7 +11521,7 @@ bc_expand_constructor (constr)
        
        
        /* Store each element of the constructor into the corresponding
-          element of TARGET, determined by counting the elements. */
+          element of TARGET, determined by counting the elements.  */
        
        for (elt = CONSTRUCTOR_ELTS (constr), i = 0;
             elt;
@@ -11374,6 +11601,7 @@ bc_store_field (field, bitsize, bitpos, mode, exp, type,
 
 
 /* Store SI/SU in bitfield */
+
 void
 bc_store_bit_field (offset, size, unsignedp)
      int offset, size, unsignedp;
@@ -11387,6 +11615,7 @@ bc_store_bit_field (offset, size, unsignedp)
 
 
 /* Load SI/SU from bitfield */
+
 void
 bc_load_bit_field (offset, size, unsignedp)
      int offset, size, unsignedp;
@@ -11396,13 +11625,13 @@ bc_load_bit_field (offset, size, unsignedp)
 
   /* Load: sign-extend if signed, else zero-extend */
   bc_emit_instruction (unsignedp ? zxloadBI : sxloadBI);
-}  
+}
 
 
 /* Adjust interpreter stack by NLEVELS.  Positive means drop NLEVELS
    (adjust stack pointer upwards), negative means add that number of
    levels (adjust the stack pointer downwards).  Only positive values
-   normally make sense. */
+   normally make sense.  */
 
 void
 bc_adjust_stack (nlevels)