OSDN Git Service

(expand_return): In code for doing scc with jumps,
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index be7c78c..d79546e 100644 (file)
@@ -26,6 +26,8 @@ Boston, MA 02111-1307, USA.  */
 #include "obstack.h"
 #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"
@@ -153,7 +155,7 @@ extern int local_vars_size;
 extern int stack_depth;
 extern int max_stack_depth;
 extern struct obstack permanent_obstack;
-
+extern rtx arg_pointer_save_area;
 
 static rtx enqueue_insn                PROTO((rtx, rtx));
 static int queued_subexp_p     PROTO((rtx));
@@ -186,9 +188,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,7 +211,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
@@ -239,7 +239,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
@@ -253,13 +253,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,9 +612,9 @@ convert_move (to, from, unsignedp)
       rtx value;
 
 #ifdef HAVE_extendqfhf2
-      if (HAVE_extendqfsf2 && from_mode == QFmode && to_mode == HFmode)
+      if (HAVE_extendqfhf2 && from_mode == QFmode && to_mode == HFmode)
        {
-         emit_unop_insn (CODE_FOR_extendqfsf2, to, from, UNKNOWN);
+         emit_unop_insn (CODE_FOR_extendqfhf2, to, from, UNKNOWN);
          return;
        }
 #endif
@@ -1817,6 +1818,92 @@ 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;
+         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;
+      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.  */
 
@@ -1850,6 +1937,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
@@ -2349,6 +2458,12 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
      Default is below for small data on big-endian machines; else above.  */
   enum direction where_pad = FUNCTION_ARG_PADDING (mode, type);
 
+  /* If we're placing part of X into a register and part of X onto
+     the stack, indicate that the entire register is clobbered to
+     keep flow from thinking the unused part of the register is live.  */
+  if (partial > 0 && reg != 0)
+    emit_insn (gen_rtx (CLOBBER, VOIDmode, reg));
+
   /* Invert direction if stack is post-update.  */
   if (STACK_PUSH_CODE == POST_INC || STACK_PUSH_CODE == POST_DEC)
     if (where_pad != none)
@@ -2642,7 +2757,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));
@@ -2686,7 +2808,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;
@@ -2796,6 +2918,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;
@@ -2805,7 +2928,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
@@ -2929,6 +3056,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);
@@ -2937,14 +3075,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)
@@ -3160,6 +3358,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);
@@ -3245,7 +3447,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++;
@@ -3260,7 +3462,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,
@@ -3272,14 +3479,17 @@ store_constructor_field (target, bitsize, bitpos,
      int cleared;
 {
   if (TREE_CODE (exp) == CONSTRUCTOR
-      && (bitpos % BITS_PER_UNIT) == 0)
-    {
-      bitpos /= BITS_PER_UNIT;
-      store_constructor (exp,
-                        change_address (target, VOIDmode,
-                                        plus_constant (XEXP (target, 0),
-                                                       bitpos)),
-                        cleared);
+      && 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,
+                                plus_constant (XEXP (target, 0),
+                                               bitpos / BITS_PER_UNIT));
+      store_constructor (exp, target, cleared);
     }
   else
     store_field (target, bitsize, bitpos, mode, exp,
@@ -3289,7 +3499,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)
@@ -3472,7 +3682,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 +3727,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 +3767,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 +3786,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 +3796,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 +3856,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 +3885,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 +3907,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 +3931,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 +3989,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
@@ -3899,6 +4111,27 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
          && 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)
@@ -4078,11 +4311,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)
@@ -4134,15 +4365,6 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
       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 (integer_zerop (offset))
     offset = 0;
 
@@ -4302,12 +4524,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 +4638,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 ();
        }
 
@@ -4578,7 +4805,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 +4856,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 +4871,7 @@ expand_expr (exp, target, tmode, modifier)
          pop_obstacks ();
        }
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case FUNCTION_DECL:
     case RESULT_DECL:
@@ -4681,6 +4908,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 +5075,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,6 +5090,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
@@ -5034,27 +5271,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 +5340,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));
@@ -5280,7 +5498,8 @@ expand_expr (exp, target, tmode, modifier)
                            && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
                                != INTEGER_CST)
                            ? target : NULL_RTX),
-                          VOIDmode, 0);
+                          VOIDmode,
+                          modifier == EXPAND_INITIALIZER ? modifier : 0);
 
        /* If this is a constant, put it into a register if it is a
           legitimate constant and memory if it isn't.  */
@@ -5325,11 +5544,12 @@ 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])
                    /* If the field isn't aligned enough to fetch as a memref,
@@ -5344,7 +5564,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);
 
@@ -5396,22 +5636,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.  */
@@ -5536,7 +5760,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);
 
@@ -5645,7 +5869,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;
 
@@ -6164,7 +6389,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
@@ -6238,7 +6463,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;
 
@@ -6290,6 +6515,8 @@ expand_expr (exp, target, tmode, modifier)
                 && ! (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);
 
@@ -6390,7 +6617,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.  */
@@ -6436,7 +6663,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;
@@ -6461,7 +6688,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;
@@ -6481,7 +6708,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;
@@ -6492,7 +6719,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);
@@ -6501,7 +6728,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 ();
@@ -6516,14 +6743,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;
@@ -6531,18 +6758,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);
@@ -6551,7 +6778,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;
@@ -6569,17 +6796,16 @@ 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;
       }
 
     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
@@ -6590,6 +6816,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;
 
@@ -6625,13 +6852,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
@@ -6656,16 +6877,21 @@ 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);
+       if (cleanups)
+         {
+           cleanups_this_call = tree_cons (NULL_TREE,
+                                           cleanups,
+                                           cleanups_this_call);
+           expand_eh_region_start ();
+         }
        
-       return temp;
+       return target;
       }
 
     case INIT_EXPR:
@@ -6758,21 +6984,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);
@@ -6816,7 +7043,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);
 
@@ -6972,7 +7199,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;
@@ -7087,7 +7315,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));
@@ -7108,7 +7336,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
@@ -7744,7 +7972,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:
@@ -7830,7 +8058,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;
@@ -7839,7 +8067,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);
@@ -8045,10 +8273,13 @@ expand_builtin (exp, target, subtarget, mode, ignore)
            tree arg = TREE_VALUE (arglist);
 
            /* Strip off all nops for the sake of the comparison.  This
-              is not quite the same as STRIP_NOPS.  It does more.  */
+              is not quite the same as STRIP_NOPS.  It does more.  
+              We must also strip off INDIRECT_EXPR for C++ reference
+              parameters.  */
            while (TREE_CODE (arg) == NOP_EXPR
                   || TREE_CODE (arg) == CONVERT_EXPR
-                  || TREE_CODE (arg) == NON_LVALUE_EXPR)
+                  || TREE_CODE (arg) == NON_LVALUE_EXPR
+                  || TREE_CODE (arg) == INDIRECT_REF)
              arg = TREE_OPERAND (arg, 0);
            if (arg != last_parm)
              warning ("second parameter of `va_start' not last named argument");
@@ -8216,15 +8447,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)
            {
@@ -8362,6 +8593,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.  */
@@ -8492,6 +8775,240 @@ 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 = 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;
+       int old_inhibit_defer_pop = inhibit_defer_pop;
+       int return_pops = RETURN_POPS_ARGS (get_identifier ("__dummy"),
+                                           get_identifier ("__dummy"), 0);
+       rtx next_arg_reg;
+       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);
+
+       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);
+
+       current_function_has_nonlocal_goto = 1;
+
+#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;
+      }
+
+      /* __builtin_longjmp is passed a pointer to an array of five words
+        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
+         || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
+       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,
+                                          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)));
+       enum machine_mode sa_mode
+#ifdef HAVE_save_stack_nonlocal
+         = (HAVE_save_stack_nonlocal
+            ? insn_operand_mode[(int) CODE_FOR_save_stack_nonlocal][0]
+            : Pmode);
+#else
+       = Pmode;
+#endif
+       rtx stack = gen_rtx (MEM, sa_mode,
+                            plus_constant (buf_addr,
+                                           2 * GET_MODE_SIZE (Pmode)));
+
+       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,
+                                       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 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 (lab);
+       }
+
+       return const0_rtx;
+      }
+
     default:                   /* just do library call, if unknown builtin */
       error ("built-in function `%s' not currently supported",
             IDENTIFIER_POINTER (DECL_NAME (fndecl)));
@@ -8522,12 +9039,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)
@@ -8536,7 +9053,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
@@ -8986,9 +9503,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;
@@ -9119,7 +9636,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;
     }
 
@@ -9194,16 +9711,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:
@@ -9290,7 +9808,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);
     }      
@@ -9333,7 +9851,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);
     }
@@ -9497,20 +10015,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);
 
@@ -9518,7 +10036,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;
@@ -9532,10 +10050,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
          {
@@ -9561,20 +10079,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);
 
@@ -9582,7 +10100,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;
@@ -9596,10 +10114,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
          {
@@ -9612,6 +10130,7 @@ do_jump (exp, if_false_label, if_true_label)
     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 ();
@@ -10129,6 +10648,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),
@@ -10182,7 +10727,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
@@ -10263,6 +10808,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);
 
@@ -10328,10 +10886,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.  */
 
@@ -10540,7 +11113,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)
@@ -10551,7 +11124,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
@@ -10560,7 +11133,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;
@@ -10580,7 +11153,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)
@@ -10606,7 +11179,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;
@@ -10662,7 +11235,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)
@@ -10685,6 +11258,7 @@ bc_allocate_variable_array (size)
 
 
 /* Push the machine address for the given external variable offset.  */
+
 void
 bc_load_externaddr (externaddr)
      rtx externaddr;
@@ -10699,17 +11273,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;
@@ -10719,7 +11284,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);
@@ -10728,6 +11293,7 @@ bc_load_externaddr_id (id, offset)
 
 
 /* Push the machine address for the given local variable offset.  */
+
 void
 bc_load_localaddr (localaddr)
      rtx localaddr;
@@ -10737,7 +11303,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;
@@ -10748,6 +11315,7 @@ bc_load_parmaddr (parmaddr)
 
 
 /* Convert a[i] into *(a + i).  */
+
 tree
 bc_canonicalize_array_ref (exp)
      tree exp;
@@ -10783,7 +11351,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)
@@ -10833,6 +11401,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;
@@ -10846,7 +11415,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)
@@ -10873,7 +11442,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)))
@@ -10960,7 +11529,7 @@ bc_expand_address (exp)
       break;
     }
 
-  /* Most lvalues don't have components. */
+  /* Most lvalues don't have components.  */
   return (exp);
 }
 
@@ -11002,6 +11571,7 @@ bc_runtime_type_code (type)
 
 
 /* Generate constructor label */
+
 char *
 bc_gen_constr_label ()
 {
@@ -11019,7 +11589,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)
@@ -11032,7 +11602,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.
    */
@@ -11057,18 +11627,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)
@@ -11135,7 +11705,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;
@@ -11215,6 +11785,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;
@@ -11228,6 +11799,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;
@@ -11243,7 +11815,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)