OSDN Git Service

(location_or_const_value_attribute, case CONCAT): Add.
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index 6678d30..595d131 100644 (file)
@@ -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"
@@ -176,6 +177,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));
@@ -189,7 +191,6 @@ static rtx expand_builtin_apply     PROTO((rtx, rtx, rtx));
 static void expand_builtin_return PROTO((rtx));
 static rtx expand_increment    PROTO((tree, int, int));
 void bc_expand_increment       PROTO((struct increment_operator *, tree));
-tree bc_runtime_type_code      PROTO((tree));
 rtx bc_allocate_local          PROTO((int, int));
 void bc_store_memory           PROTO((tree, tree));
 tree bc_expand_component_address PROTO((tree));
@@ -211,7 +212,6 @@ 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 +240,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,13 +254,14 @@ 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 ()
 {
@@ -611,115 +612,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)
+      if (GET_MODE_BITSIZE (from_mode) < GET_MODE_BITSIZE (to_mode))
        {
-         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)
-       {
-         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 +694,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 +1292,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 +1463,7 @@ move_by_pieces (to, from, len, align)
     }
 
   /* The code above should have handled everything.  */
-  if (data.len != 0)
+  if (data.len > 0)
     abort ();
 }
 
@@ -1818,6 +1764,100 @@ 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)))
+           source = gen_rtx (SUBREG, GET_MODE (target_reg), y, 0);
+         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 +1891,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
@@ -2649,7 +2711,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));
@@ -2693,7 +2762,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;
@@ -2722,8 +2791,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.  */
@@ -2731,7 +2800,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)
        {
@@ -2742,14 +2810,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)
        {
@@ -2813,7 +2873,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,6 +3001,17 @@ store_expr (exp, target, want_value)
         For non-BLKmode, it is more efficient not to do this.  */
 
       rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
+      rtx flag = NULL_RTX;
+      tree left_cleanups = NULL_TREE;
+      tree right_cleanups = NULL_TREE;
+      tree old_cleanups = cleanups_this_call;
+
+      /* 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;
 
       emit_queue ();
       target = protect_from_queue (target, 1);
@@ -2945,14 +3020,74 @@ store_expr (exp, target, want_value)
       NO_DEFER_POP;
       jumpifnot (TREE_OPERAND (exp, 0), lab1);
       store_expr (TREE_OPERAND (exp, 1), target, 0);
+      dest_left_flag = get_last_insn ();
+      /* Handle conditional cleanups, if any.  */
+      left_cleanups = defer_cleanups_to (old_cleanups);
       emit_queue ();
       emit_jump_insn (gen_jump (lab2));
       emit_barrier ();
       emit_label (lab1);
       store_expr (TREE_OPERAND (exp, 2), target, 0);
+      dest_right_flag = get_last_insn ();
+      /* Handle conditional cleanups, if any.  */
+      right_cleanups = defer_cleanups_to (old_cleanups);
       emit_queue ();
       emit_label (lab2);
       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.  */
+
+         flag = gen_reg_rtx (word_mode);
+
+         /* 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);
+         expand_eh_region_start ();
+       }
       return want_value ? target : NULL_RTX;
     }
   else if (want_value && GET_CODE (target) == MEM && ! MEM_VOLATILE_P (target)
@@ -2998,8 +3133,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))
@@ -3148,7 +3286,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,
@@ -3156,7 +3294,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)),
@@ -3168,6 +3306,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);
@@ -3253,7 +3395,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++;
@@ -3305,7 +3447,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)
@@ -3465,7 +3607,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;
@@ -3489,7 +3631,7 @@ store_constructor (exp, target, cleared)
                zero_count += this_node_count;
            }
          /* Clear the entire array first if there are any missing elements,
-            or if the incidence of zero elements is >= 75%. */
+            or if the incidence of zero elements is >= 75%.  */
          if (count < maxelt - minelt + 1
              || 4 * zero_count >= 3 * count)
            need_to_clear = 1;
@@ -3536,7 +3678,7 @@ store_constructor (exp, target, cleared)
              HOST_WIDE_INT lo, hi, count;
              tree position;
 
-             /* If the range is constant and "small", unroll the loop. */
+             /* If the range is constant and "small", unroll the loop.  */
              if (TREE_CODE (lo_index) == INTEGER_CST
                  && TREE_CODE (hi_index) == INTEGER_CST
                  && (lo = TREE_INT_CST_LOW (lo_index),
@@ -3573,14 +3715,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,
@@ -3661,9 +3804,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)
@@ -3690,11 +3833,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 (;;)
            {
@@ -3712,8 +3855,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);
@@ -3735,7 +3879,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
@@ -3793,7 +3937,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
@@ -3909,12 +4053,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)
@@ -4010,6 +4187,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.
@@ -4020,11 +4200,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;
@@ -4032,11 +4212,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)
     {
@@ -4094,11 +4276,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)
@@ -4147,22 +4327,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,
-                           (TYPE_MODE (TREE_TYPE (orig_exp)) == BLKmode
-                            ? MODE_INT
-                            : GET_MODE_CLASS (TYPE_MODE
-                                              (TREE_TYPE (orig_exp)))),
-                           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;
@@ -4172,6 +4349,7 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
 
   *pmode = mode;
   *poffset = offset;
+  *palignment = alignment / BITS_PER_UNIT;
   return exp;
 }
 \f
@@ -4323,12 +4501,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;
 
@@ -4432,7 +4615,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 ();
        }
 
@@ -4485,6 +4668,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.
@@ -4599,7 +4800,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);
 
@@ -4650,7 +4851,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,
@@ -4665,7 +4866,7 @@ expand_expr (exp, target, tmode, modifier)
          pop_obstacks ();
        }
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case FUNCTION_DECL:
     case RESULT_DECL:
@@ -4869,7 +5070,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)
@@ -4884,6 +5085,14 @@ 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
@@ -5032,7 +5241,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);
@@ -5126,7 +5338,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));
@@ -5265,9 +5477,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
@@ -5298,7 +5511,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);
@@ -5308,14 +5520,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.  */
@@ -5337,7 +5541,9 @@ expand_expr (exp, target, tmode, modifier)
            || GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
            || (modifier != EXPAND_CONST_ADDRESS
                && 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
@@ -5350,7 +5556,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);
 
@@ -5361,6 +5587,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,
@@ -5402,22 +5640,6 @@ expand_expr (exp, target, tmode, modifier)
        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.  */
@@ -5542,7 +5764,7 @@ expand_expr (exp, target, tmode, modifier)
            = tree_cons (NULL_TREE, TREE_OPERAND (exp, 2), cleanups_this_call);
          /* That's it for this cleanup.  */
          TREE_OPERAND (exp, 2) = 0;
-         (*interim_eh_hook) (NULL_TREE);
+         expand_eh_region_start ();
        }
       return RTL_EXPR_RTL (exp);
 
@@ -5651,7 +5873,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;
 
@@ -6170,7 +6393,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
@@ -6244,7 +6467,7 @@ expand_expr (exp, target, tmode, modifier)
        /* 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. */
+          have any conditional cleanups that need to be performed.  */
        rtx dest_right_flag = NULL_RTX;
        rtx dest_left_flag = NULL_RTX;
 
@@ -6283,22 +6506,6 @@ 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
@@ -6322,6 +6529,27 @@ 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 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 + 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.  */
@@ -6396,7 +6624,7 @@ expand_expr (exp, target, tmode, modifier)
            else
              jumpifnot (TREE_OPERAND (exp, 0), op0);
 
-           /* Allows cleanups up to here. */
+           /* Allows cleanups up to here.  */
            old_cleanups = cleanups_this_call;
            if (binary_op && temp == 0)
              /* Just touch the other operand.  */
@@ -6442,7 +6670,7 @@ expand_expr (exp, target, tmode, modifier)
            dest_left_flag = get_last_insn ();
            jumpifnot (TREE_OPERAND (exp, 0), op0);
 
-           /* Allows cleanups up to here. */
+           /* Allows cleanups up to here.  */
            old_cleanups = cleanups_this_call;
            store_expr (TREE_OPERAND (exp, 1), temp, 0);
            op1 = op0;
@@ -6467,7 +6695,7 @@ expand_expr (exp, target, tmode, modifier)
            dest_left_flag = get_last_insn ();
            jumpif (TREE_OPERAND (exp, 0), op0);
 
-           /* Allows cleanups up to here. */
+           /* Allows cleanups up to here.  */
            old_cleanups = cleanups_this_call;
            store_expr (TREE_OPERAND (exp, 2), temp, 0);
            op1 = op0;
@@ -6487,7 +6715,7 @@ expand_expr (exp, target, tmode, modifier)
            dest_left_flag = get_last_insn ();
            jumpifnot (TREE_OPERAND (exp, 0), op0);
 
-           /* Allows cleanups up to here. */
+           /* Allows cleanups up to here.  */
            old_cleanups = cleanups_this_call;
            store_expr (TREE_OPERAND (exp, 1), temp, 0);
            op1 = op0;
@@ -6498,7 +6726,7 @@ expand_expr (exp, target, tmode, modifier)
            op1 = gen_label_rtx ();
            jumpifnot (TREE_OPERAND (exp, 0), op0);
 
-           /* Allows cleanups up to here. */
+           /* Allows cleanups up to here.  */
            old_cleanups = cleanups_this_call;
            if (temp != 0)
              store_expr (TREE_OPERAND (exp, 1), temp, 0);
@@ -6507,7 +6735,7 @@ expand_expr (exp, target, tmode, modifier)
                           ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
            dest_left_flag = get_last_insn ();
 
-           /* Handle conditional cleanups, if any. */
+           /* Handle conditional cleanups, if any.  */
            left_cleanups = defer_cleanups_to (old_cleanups);
 
            emit_queue ();
@@ -6522,14 +6750,14 @@ expand_expr (exp, target, tmode, modifier)
            dest_right_flag = get_last_insn ();
          }
 
-       /* Handle conditional cleanups, if any. */
+       /* Handle conditional cleanups, if any.  */
        right_cleanups = defer_cleanups_to (old_cleanups);
 
        emit_queue ();
        emit_label (op1);
        OK_DEFER_POP;
 
-       /* Add back in, any conditional cleanups. */
+       /* Add back in, any conditional cleanups.  */
        if (left_cleanups || right_cleanups)
          {
            tree new_cleanups;
@@ -6537,18 +6765,18 @@ expand_expr (exp, target, tmode, modifier)
            rtx last;
 
            /* Now that we know that a flag is needed, go back and add in the
-              setting of the flag. */
+              setting of the flag.  */
 
-           /* Do the left side flag. */
+           /* Do the left side flag.  */
            last = get_last_insn ();
-           /* Flag left cleanups as needed. */
+           /* 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. */
+           /* Do the right side flag.  */
            last = get_last_insn ();
-           /* Flag left cleanups as needed. */
+           /* 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);
@@ -6557,7 +6785,7 @@ expand_expr (exp, target, tmode, modifier)
            push_obstacks_nochange ();
            resume_temporary_allocation ();
 
-           /* convert flag, which is an rtx, into a tree. */
+           /* 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;
@@ -6575,10 +6803,10 @@ expand_expr (exp, target, tmode, modifier)
 
            pop_obstacks ();
 
-           /* Now add in the conditionalized cleanups. */
+           /* Now add in the conditionalized cleanups.  */
            cleanups_this_call
              = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
-           (*interim_eh_hook) (NULL_TREE);
+           expand_eh_region_start ();
          }
        return temp;
       }
@@ -6656,7 +6884,7 @@ 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;
 
@@ -6667,7 +6895,7 @@ expand_expr (exp, target, tmode, modifier)
            cleanups_this_call = tree_cons (NULL_TREE,
                                            cleanups,
                                            cleanups_this_call);
-           (*interim_eh_hook) (NULL_TREE);
+           expand_eh_region_start ();
          }
        
        return target;
@@ -6772,7 +7000,7 @@ expand_expr (exp, target, tmode, modifier)
 
     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?  */
@@ -6822,7 +7050,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);
 
@@ -6978,7 +7206,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;
@@ -7093,7 +7322,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));
@@ -7114,7 +7343,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
@@ -7667,8 +7896,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;
 
@@ -7750,7 +7979,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:
@@ -7836,7 +8065,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;
@@ -7845,7 +8074,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);
@@ -8225,15 +8454,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)
            {
@@ -8371,6 +8600,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.  */
@@ -8516,9 +8797,8 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        break;
 
       {
-       rtx buf_addr
-         = force_reg (Pmode, expand_expr (TREE_VALUE (arglist), subtarget,
-                                          VOIDmode, 0));
+       rtx buf_addr = 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;
@@ -8529,6 +8809,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        CUMULATIVE_ARGS args_so_far;
        int i;
 
+#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);
@@ -8615,6 +8901,10 @@ expand_builtin (exp, target, subtarget, mode, ignore)
          }
 #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.  */
@@ -8663,9 +8953,19 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        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, expand_expr (TREE_VALUE (arglist), NULL_RTX,
+         = 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,
                                           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)));
@@ -8746,12 +9046,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)
@@ -8760,7 +9060,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
@@ -9371,6 +9671,22 @@ expand_increment (exp, post, ignore)
 
          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.  */
@@ -9515,7 +9831,7 @@ defer_cleanups_to (old_cleanups)
 
   while (cleanups_this_call != old_cleanups)
     {
-      (*interim_eh_hook) (TREE_VALUE (cleanups_this_call));
+      expand_eh_region_end (TREE_VALUE (cleanups_this_call));
       last = cleanups_this_call;
       cleanups_this_call = TREE_CHAIN (cleanups_this_call);
     }      
@@ -9558,7 +9874,7 @@ expand_cleanups_to (old_cleanups)
 {
   while (cleanups_this_call != old_cleanups)
     {
-      (*interim_eh_hook) (TREE_VALUE (cleanups_this_call));
+      expand_eh_region_end (TREE_VALUE (cleanups_this_call));
       expand_expr (TREE_VALUE (cleanups_this_call), const0_rtx, VOIDmode, 0);
       cleanups_this_call = TREE_CHAIN (cleanups_this_call);
     }
@@ -9722,20 +10038,20 @@ do_jump (exp, if_false_label, if_true_label)
        start_sequence ();
        do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
        seq2 = get_insns ();
+       cleanups = defer_cleanups_to (old_cleanups);
        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. */
+           /* Flag cleanups as not needed.  */
            emit_move_insn (flag, const0_rtx);
            emit_insns (seq1);
 
-           /* Flag cleanups as needed. */
+           /* Flag cleanups as needed.  */
            emit_move_insn (flag, const1_rtx);
            emit_insns (seq2);
 
@@ -9743,7 +10059,7 @@ do_jump (exp, if_false_label, if_true_label)
            push_obstacks_nochange ();
            resume_temporary_allocation ();
 
-           /* convert flag, which is an rtx, into a tree. */
+           /* 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;
@@ -9757,10 +10073,10 @@ do_jump (exp, if_false_label, if_true_label)
 
            pop_obstacks ();
 
-           /* Now add in the conditionalized cleanups. */
+           /* Now add in the conditionalized cleanups.  */
            cleanups_this_call
              = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
-           (*interim_eh_hook) (NULL_TREE);
+           expand_eh_region_start ();
          }
        else
          {
@@ -9786,20 +10102,20 @@ do_jump (exp, if_false_label, if_true_label)
        start_sequence ();
        do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
        seq2 = get_insns ();
+       cleanups = defer_cleanups_to (old_cleanups);
        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. */
+           /* Flag cleanups as not needed.  */
            emit_move_insn (flag, const0_rtx);
            emit_insns (seq1);
 
-           /* Flag cleanups as needed. */
+           /* Flag cleanups as needed.  */
            emit_move_insn (flag, const1_rtx);
            emit_insns (seq2);
 
@@ -9807,7 +10123,7 @@ do_jump (exp, if_false_label, if_true_label)
            push_obstacks_nochange ();
            resume_temporary_allocation ();
 
-           /* convert flag, which is an rtx, into a tree. */
+           /* 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;
@@ -9821,10 +10137,10 @@ do_jump (exp, if_false_label, if_true_label)
 
            pop_obstacks ();
 
-           /* Now add in the conditionalized cleanups. */
+           /* Now add in the conditionalized cleanups.  */
            cleanups_this_call
              = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
-           (*interim_eh_hook) (NULL_TREE);
+           expand_eh_region_start ();
          }
        else
          {
@@ -9854,11 +10170,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
@@ -9885,9 +10203,18 @@ do_jump (exp, if_false_label, if_true_label)
 
       else
        {
+         rtx seq1, seq2;
+         tree cleanups_left_side, cleanups_right_side, old_cleanups;
+
          register rtx label1 = gen_label_rtx ();
          drop_through_label = gen_label_rtx ();
+
          do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX);
+
+         /* We need to save the cleanups for the lhs and rhs separately. 
+            Keep track of the cleanups seen before the lhs. */
+         old_cleanups = cleanups_this_call;
+         start_sequence ();
          /* Now the THEN-expression.  */
          do_jump (TREE_OPERAND (exp, 1),
                   if_false_label ? if_false_label : drop_through_label,
@@ -9895,10 +10222,71 @@ 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);
+         seq1 = get_insns ();
+         /* Now grab the cleanups for the lhs. */
+         cleanups_left_side = defer_cleanups_to (old_cleanups);
+         end_sequence ();
+
+         /* And keep track of where we start before the rhs. */
+         old_cleanups = cleanups_this_call;
+         start_sequence ();
          /* 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);
+         seq2 = get_insns ();
+         /* Grab the cleanups for the rhs. */
+         cleanups_right_side = defer_cleanups_to (old_cleanups);
+         end_sequence ();
+
+         if (cleanups_left_side || cleanups_right_side)
+           {
+             /* Make the cleanups for the THEN and ELSE clauses
+                conditional based on which half is executed. */
+             rtx flag = gen_reg_rtx (word_mode);
+             tree new_cleanups;
+             tree cond;
+
+             /* Set the flag to 0 so that we know we executed the lhs. */
+             emit_move_insn (flag, const0_rtx);
+             emit_insns (seq1);
+
+             /* Set the flag to 1 so that we know we executed the rhs. */
+             emit_move_insn (flag, const1_rtx);
+             emit_insns (seq2);
+
+             /* Make sure the cleanup lives on the function_obstack. */
+             push_obstacks_nochange ();
+             resume_temporary_allocation ();
+
+             /* Now, build up a COND_EXPR that tests the value of the
+                flag, and then either do the cleanups for the lhs or the
+                rhs. */
+             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_right_side, cleanups_left_side);
+             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);
+             expand_eh_region_start ();
+           }
+         else 
+           {
+             /* No cleanups were needed, so emit the two sequences
+                directly. */
+             emit_insns (seq1);
+             emit_insns (seq2);
+           }
        }
       break;
 
@@ -10355,6 +10743,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),
@@ -10408,7 +10822,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
@@ -10489,6 +10903,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);
 
@@ -10676,7 +11103,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));
 
@@ -10781,7 +11208,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)
@@ -10792,7 +11219,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
@@ -10801,7 +11228,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;
@@ -10821,7 +11248,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)
@@ -10847,7 +11274,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;
@@ -10903,7 +11330,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)
@@ -10926,6 +11353,7 @@ bc_allocate_variable_array (size)
 
 
 /* Push the machine address for the given external variable offset.  */
+
 void
 bc_load_externaddr (externaddr)
      rtx externaddr;
@@ -10941,6 +11369,7 @@ bc_load_externaddr (externaddr)
 
 
 /* Like above, but expects an IDENTIFIER.  */
+
 void
 bc_load_externaddr_id (id, offset)
      tree id;
@@ -10959,6 +11388,7 @@ bc_load_externaddr_id (id, offset)
 
 
 /* Push the machine address for the given local variable offset.  */
+
 void
 bc_load_localaddr (localaddr)
      rtx localaddr;
@@ -10968,7 +11398,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;
@@ -10979,6 +11410,7 @@ bc_load_parmaddr (parmaddr)
 
 
 /* Convert a[i] into *(a + i).  */
+
 tree
 bc_canonicalize_array_ref (exp)
      tree exp;
@@ -11014,7 +11446,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)
@@ -11064,6 +11496,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;
@@ -11077,7 +11510,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)
@@ -11104,7 +11537,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)))
@@ -11191,7 +11624,7 @@ bc_expand_address (exp)
       break;
     }
 
-  /* Most lvalues don't have components. */
+  /* Most lvalues don't have components.  */
   return (exp);
 }
 
@@ -11233,6 +11666,7 @@ bc_runtime_type_code (type)
 
 
 /* Generate constructor label */
+
 char *
 bc_gen_constr_label ()
 {
@@ -11250,7 +11684,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)
@@ -11263,7 +11697,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.
    */
@@ -11288,18 +11722,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)
@@ -11366,7 +11800,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;
@@ -11446,6 +11880,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;
@@ -11459,6 +11894,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;
@@ -11474,7 +11910,7 @@ bc_load_bit_field (offset, size, unsignedp)
 /* 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)