OSDN Git Service

* pa.h (ASM_OUTPUT_SECTION_NAME): Fix typo.
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index 37950e9..b3ca539 100644 (file)
@@ -1,5 +1,5 @@
 /* Convert tree expression to rtl instructions, for GNU compiler.
-   Copyright (C) 1988, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1988, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -94,10 +94,6 @@ int pending_stack_adjust;
    and in other cases as well.  */
 int inhibit_defer_pop;
 
-/* A list of all cleanups which belong to the arguments of
-   function calls being expanded by expand_call.  */
-tree cleanups_this_call;
-
 /* When temporaries are created by TARGET_EXPRs, they are created at
    this level of temp_slot_level, so that they can remain allocated
    until no longer needed.  CLEANUP_POINT_EXPRs define the lifetime
@@ -211,7 +207,6 @@ static void do_jump_by_parts_equality_rtx PROTO((rtx, rtx, rtx));
 static void do_jump_for_compare        PROTO((rtx, rtx, rtx));
 static rtx compare             PROTO((tree, enum rtx_code, enum rtx_code));
 static rtx do_store_flag       PROTO((tree, rtx, enum machine_mode, int));
-static tree defer_cleanups_to  PROTO((tree));
 extern tree truthvalue_conversion       PROTO((tree));
 
 /* Record for each mode whether we can move a register directly to or
@@ -268,9 +263,9 @@ bc_init_mode_to_opcode_maps ()
   int mode;
 
   for (mode = 0; mode < (int) MAX_MACHINE_MODE; mode++)
-    mode_to_const_map[mode] =
-      mode_to_load_map[mode] =
-       mode_to_store_map[mode] = neverneverland;
+    mode_to_const_map[mode]
+      = mode_to_load_map[mode]
+      = mode_to_store_map[mode] = neverneverland;
       
 #define DEF_MODEMAP(SYM, CODE, UCODE, CONST, LOAD, STORE) \
   mode_to_const_map[(int) SYM] = CONST; \
@@ -357,7 +352,6 @@ init_expr ()
 
   pending_stack_adjust = 0;
   inhibit_defer_pop = 0;
-  cleanups_this_call = 0;
   saveregs_value = 0;
   apply_args_value = 0;
   forced_labels = 0;
@@ -375,14 +369,12 @@ save_expr_status (p)
 
   p->pending_stack_adjust = pending_stack_adjust;
   p->inhibit_defer_pop = inhibit_defer_pop;
-  p->cleanups_this_call = cleanups_this_call;
   p->saveregs_value = saveregs_value;
   p->apply_args_value = apply_args_value;
   p->forced_labels = forced_labels;
 
   pending_stack_adjust = 0;
   inhibit_defer_pop = 0;
-  cleanups_this_call = 0;
   saveregs_value = 0;
   apply_args_value = 0;
   forced_labels = 0;
@@ -397,7 +389,6 @@ restore_expr_status (p)
 {
   pending_stack_adjust = p->pending_stack_adjust;
   inhibit_defer_pop = p->inhibit_defer_pop;
-  cleanups_this_call = p->cleanups_this_call;
   saveregs_value = p->saveregs_value;
   apply_args_value = p->apply_args_value;
   forced_labels = p->forced_labels;
@@ -1292,7 +1283,20 @@ convert_modes (mode, oldmode, x, unsignedp)
   if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
       && GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT
       && GET_CODE (x) == CONST_INT && INTVAL (x) < 0)
-    return immed_double_const (INTVAL (x), (HOST_WIDE_INT) 0, mode);
+    {
+      HOST_WIDE_INT val = INTVAL (x);
+
+      if (oldmode != VOIDmode
+         && HOST_BITS_PER_WIDE_INT > GET_MODE_BITSIZE (oldmode))
+       {
+         int width = GET_MODE_BITSIZE (oldmode);
+
+         /* We need to zero extend VAL.  */
+         val &= ((HOST_WIDE_INT) 1 << width) - 1;
+       }
+
+      return immed_double_const (val, (HOST_WIDE_INT) 0, mode);
+    }
 
   /* We can do this with a gen_lowpart if both desired and current modes
      are integer, and this is either a constant integer, a register, or a
@@ -1450,7 +1454,7 @@ move_by_pieces (to, from, len, align)
     }
 
   /* The code above should have handled everything.  */
-  if (data.len != 0)
+  if (data.len > 0)
     abort ();
 }
 
@@ -1513,14 +1517,17 @@ move_by_pieces_1 (genfun, mode, data)
 
       to1 = (data->autinc_to
             ? gen_rtx (MEM, mode, data->to_addr)
-            : change_address (data->to, mode,
-                              plus_constant (data->to_addr, data->offset)));
+            : copy_rtx (change_address (data->to, mode,
+                                        plus_constant (data->to_addr,
+                                                       data->offset))));
       MEM_IN_STRUCT_P (to1) = data->to_struct;
-      from1 =
-       (data->autinc_from
-        ? gen_rtx (MEM, mode, data->from_addr)
-        : change_address (data->from, mode,
-                          plus_constant (data->from_addr, data->offset)));
+
+      from1
+       = (data->autinc_from
+          ? gen_rtx (MEM, mode, data->from_addr)
+          : copy_rtx (change_address (data->from, mode,
+                                      plus_constant (data->from_addr,
+                                                     data->offset))));
       MEM_IN_STRUCT_P (from1) = data->from_struct;
 
 #ifdef HAVE_PRE_DECREMENT
@@ -1704,9 +1711,21 @@ move_block_from_reg (regno, x, nregs, size)
 {
   int i;
   rtx pat, last;
+  enum machine_mode mode;
 
+  /* If SIZE is that of a mode no bigger than a word, just use that
+     mode's store operation.  */
+  if (size <= UNITS_PER_WORD
+      && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode)
+    {
+      emit_move_insn (change_address (x, mode, NULL),
+                     gen_rtx (REG, mode, regno));
+      return;
+    }
+    
   /* Blocks smaller than a word on a BYTES_BIG_ENDIAN machine must be aligned
-     to the left before storing to memory.  */
+     to the left before storing to memory.  Note that the previous test
+     doesn't handle all cases (e.g. SIZE == 3).  */
   if (size < UNITS_PER_WORD && BYTES_BIG_ENDIAN)
     {
       rtx tem = operand_subword (x, 0, 1, BLKmode);
@@ -1789,9 +1808,14 @@ emit_group_load (x, y)
             to allow for AIX with 4 DF arguments after a single SI arg.  The
             last DF argument will only load 1 word into the integer registers,
             but load a DF value into the float registers.  */
+         else if ((GET_MODE_SIZE (GET_MODE (target_reg))
+                   <= GET_MODE_SIZE (GET_MODE (y)))
+                  && GET_MODE (target_reg) == word_mode)
+           /* This might be a const_double, so we can't just use SUBREG.  */
+           source = operand_subword (y, 0, 0, VOIDmode);
          else if (GET_MODE_SIZE (GET_MODE (target_reg))
-                  <= GET_MODE_SIZE (GET_MODE (y)))
-           source = gen_rtx (SUBREG, GET_MODE (target_reg), y, 0);
+                  == GET_MODE_SIZE (GET_MODE (y)))
+           source = gen_lowpart (GET_MODE (target_reg), y);
          else
            abort ();       
        }
@@ -1833,7 +1857,11 @@ emit_group_store (x, y)
                                 plus_constant (XEXP (x, 0),
                                                INTVAL (XEXP (element, 1))));
       else if (XEXP (element, 1) == const0_rtx)
-       target = x;
+       {
+         target = x;
+         if (GET_MODE (target) != GET_MODE (source_reg))
+           target = gen_lowpart (GET_MODE (source_reg), target);
+       }
       else
        abort ();
 
@@ -2005,8 +2033,9 @@ clear_by_pieces_1 (genfun, mode, data)
 
       to1 = (data->autinc_to
             ? gen_rtx (MEM, mode, data->to_addr)
-            : change_address (data->to, mode,
-                              plus_constant (data->to_addr, data->offset)));
+            : copy_rtx (change_address (data->to, mode,
+                                        plus_constant (data->to_addr,
+                                                       data->offset))));
       MEM_IN_STRUCT_P (to1) = data->to_struct;
 
 #ifdef HAVE_PRE_DECREMENT
@@ -2395,12 +2424,6 @@ 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)
@@ -2774,8 +2797,8 @@ expand_assignment (to, from, want_value, suggest_reg)
       int alignment;
 
       push_temp_slots ();
-      tem = get_inner_reference (to, &bitsize, &bitpos, &offset,
-                                     &mode1, &unsignedp, &volatilep);
+      tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
+                                &unsignedp, &volatilep, &alignment);
 
       /* If we are going to use store_bit_field and extract_bit_field,
         make sure to_rtx will be safe for multiple use.  */
@@ -2783,7 +2806,6 @@ expand_assignment (to, from, want_value, suggest_reg)
       if (mode1 == VOIDmode && want_value)
        tem = stabilize_reference (tem);
 
-      alignment = TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT;
       to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0);
       if (offset != 0)
        {
@@ -2794,14 +2816,6 @@ expand_assignment (to, from, want_value, suggest_reg)
          to_rtx = change_address (to_rtx, VOIDmode,
                                   gen_rtx (PLUS, ptr_mode, XEXP (to_rtx, 0),
                                            force_reg (ptr_mode, offset_rtx)));
-         /* If we have a variable offset, the known alignment
-            is only that of the innermost structure containing the field.
-            (Actually, we could sometimes do better by using the
-            align of an element of the innermost array, but no need.)  */
-         if (TREE_CODE (to) == COMPONENT_REF
-             || TREE_CODE (to) == BIT_FIELD_REF)
-           alignment
-             = TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (to, 0))) / BITS_PER_UNIT;
        }
       if (volatilep)
        {
@@ -2811,7 +2825,8 @@ expand_assignment (to, from, want_value, suggest_reg)
                 structure we are storing into, and hence may be shared.
                 We must make a new MEM before setting the volatile bit.  */
              if (offset == 0)
-               to_rtx = change_address (to_rtx, VOIDmode, XEXP (to_rtx, 0));
+               to_rtx = copy_rtx (to_rtx);
+
              MEM_VOLATILE_P (to_rtx) = 1;
            }
 #if 0  /* This was turned off because, when a field is volatile
@@ -2993,17 +3008,6 @@ 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);
@@ -3011,75 +3015,20 @@ store_expr (exp, target, want_value)
       do_pending_stack_adjust ();
       NO_DEFER_POP;
       jumpifnot (TREE_OPERAND (exp, 0), lab1);
+      start_cleanup_deferal ();
       store_expr (TREE_OPERAND (exp, 1), target, 0);
-      dest_left_flag = get_last_insn ();
-      /* Handle conditional cleanups, if any.  */
-      left_cleanups = defer_cleanups_to (old_cleanups);
+      end_cleanup_deferal ();
       emit_queue ();
       emit_jump_insn (gen_jump (lab2));
       emit_barrier ();
       emit_label (lab1);
+      start_cleanup_deferal ();
       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);
+      end_cleanup_deferal ();
       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)
@@ -3178,7 +3127,7 @@ store_expr (exp, target, want_value)
       if (!(target && GET_CODE (target) == REG
            && REGNO (target) < FIRST_PSEUDO_REGISTER)
          && !(GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
-         && temp != target
+         && ! rtx_equal_p (temp, target)
          && (CONSTANT_P (temp) || want_value))
        dont_return_target = 1;
     }
@@ -3196,7 +3145,7 @@ store_expr (exp, target, want_value)
   /* If value was not generated in the target, store it there.
      Convert the value to TARGET's type first if nec.  */
 
-  if (temp != target && TREE_CODE (exp) != ERROR_MARK)
+  if (! rtx_equal_p (temp, target) && TREE_CODE (exp) != ERROR_MARK)
     {
       target = protect_from_queue (target, 1);
       if (GET_MODE (temp) != GET_MODE (target)
@@ -3566,8 +3515,8 @@ store_constructor (exp, target, cleared)
          if (TREE_READONLY (field))
            {
              if (GET_CODE (to_rtx) == MEM)
-               to_rtx = change_address (to_rtx, GET_MODE (to_rtx),
-                                        XEXP (to_rtx, 0));
+               to_rtx = copy_rtx (to_rtx);
+
              RTX_UNCHANGING_P (to_rtx) = 1;
            }
 
@@ -4130,8 +4079,10 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
 
       /* Now build a reference to just the desired component.  */
 
-      to_rtx = change_address (target, mode,
-                              plus_constant (addr, (bitpos / BITS_PER_UNIT)));
+      to_rtx = copy_rtx (change_address (target, mode,
+                                        plus_constant (addr,
+                                                       (bitpos
+                                                        / BITS_PER_UNIT))));
       MEM_IN_STRUCT_P (to_rtx) = 1;
 
       return store_expr (exp, to_rtx, value_mode != VOIDmode);
@@ -4179,6 +4130,9 @@ get_inner_unaligned_p (exp)
    giving the variable offset (in units) in *POFFSET.
    This offset is in addition to the bit position.
    If the position is not variable, we store 0 in *POFFSET.
+   We set *PALIGNMENT to the alignment in bytes of the address that will be
+   computed.  This is the alignment of the thing we return if *POFFSET
+   is zero, but can be more less strictly aligned if *POFFSET is nonzero.
 
    If any of the extraction expressions is volatile,
    we store 1 in *PVOLATILEP.  Otherwise we don't change that.
@@ -4189,11 +4143,11 @@ get_inner_unaligned_p (exp)
 
    If the field describes a variable-sized object, *PMODE is set to
    VOIDmode and *PBITSIZE is set to -1.  An access cannot be made in
-   this case, but the address of the object can be found.  */
+   this case, but the address of the object can be found.   */
 
 tree
 get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
-                    punsignedp, pvolatilep)
+                    punsignedp, pvolatilep, palignment)
      tree exp;
      int *pbitsize;
      int *pbitpos;
@@ -4201,11 +4155,13 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
      enum machine_mode *pmode;
      int *punsignedp;
      int *pvolatilep;
+     int *palignment;
 {
   tree orig_exp = exp;
   tree size_tree = 0;
   enum machine_mode mode = VOIDmode;
   tree offset = integer_zero_node;
+  int alignment = BIGGEST_ALIGNMENT;
 
   if (TREE_CODE (exp) == COMPONENT_REF)
     {
@@ -4291,7 +4247,8 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
            }
 
          index = fold (build (MULT_EXPR, index_type, index,
-                              TYPE_SIZE (TREE_TYPE (exp))));
+                              convert (index_type,
+                                       TYPE_SIZE (TREE_TYPE (exp)))));
 
          if (TREE_CODE (index) == INTEGER_CST
              && TREE_INT_CST_HIGH (index) == 0)
@@ -4314,9 +4271,20 @@ 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 (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;
 
@@ -4325,6 +4293,7 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
 
   *pmode = mode;
   *poffset = offset;
+  *palignment = alignment / BITS_PER_UNIT;
   return exp;
 }
 \f
@@ -5074,22 +5043,33 @@ expand_expr (exp, target, tmode, modifier)
         further information, see tree.def.  */
       if (placeholder_list)
        {
-         tree object;
+         tree need_type = TYPE_MAIN_VARIANT (type);
+         tree object = 0;
          tree old_list = placeholder_list;
+         tree elt;
 
-         for (object = TREE_PURPOSE (placeholder_list);
-              (TYPE_MAIN_VARIANT (TREE_TYPE (object))
-               != TYPE_MAIN_VARIANT (type))
-              && (TREE_CODE_CLASS (TREE_CODE (object)) == 'r'
-                  || TREE_CODE_CLASS (TREE_CODE (object)) == '1'
-                  || TREE_CODE_CLASS (TREE_CODE (object)) == '2'
-                  || TREE_CODE_CLASS (TREE_CODE (object)) == 'e');
-              object = TREE_OPERAND (object, 0))
-           ;
-
-         if (object != 0
-             && (TYPE_MAIN_VARIANT (TREE_TYPE (object))
-                 == TYPE_MAIN_VARIANT (type)))
+         /* See if the object is the type that we want.  Then see if
+            the operand of any reference is the type we want.  */
+         if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_PURPOSE (placeholder_list)))
+              == need_type))
+           object = TREE_PURPOSE (placeholder_list);
+
+         /* Find the innermost reference that is of the type we want.    */
+         for (elt = TREE_PURPOSE (placeholder_list);
+              elt != 0
+              && (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+                  || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+                  || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+                  || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e');
+              elt = ((TREE_CODE (elt) == COMPOUND_EXPR
+                      || TREE_CODE (elt) == COND_EXPR)
+                     ? TREE_OPERAND (elt, 1) : TREE_OPERAND (elt, 0)))
+           if (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+               && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (elt, 0)))
+                   == need_type))
+             object = TREE_OPERAND (elt, 0);
+
+         if (object != 0)
            {
              /* Expand this object skipping the list entries before
                 it was found in case it is also a PLACEHOLDER_EXPR.
@@ -5135,7 +5115,7 @@ expand_expr (exp, target, tmode, modifier)
        int vars_need_expansion = 0;
 
        /* Need to open a binding contour here because
-          if there are any cleanups they most be contained here.  */
+          if there are any cleanups they must be contained here.  */
        expand_start_bindings (0);
 
        /* Mark the corresponding BLOCK for output in its proper place.  */
@@ -5163,10 +5143,13 @@ expand_expr (exp, target, tmode, modifier)
       }
 
     case RTL_EXPR:
-      if (RTL_EXPR_SEQUENCE (exp) == const0_rtx)
-       abort ();
-      emit_insns (RTL_EXPR_SEQUENCE (exp));
-      RTL_EXPR_SEQUENCE (exp) = const0_rtx;
+      if (RTL_EXPR_SEQUENCE (exp))
+       {
+         if (RTL_EXPR_SEQUENCE (exp) == const0_rtx)
+           abort ();
+         emit_insns (RTL_EXPR_SEQUENCE (exp));
+         RTL_EXPR_SEQUENCE (exp) = const0_rtx;
+       }
       preserve_rtl_expr_result (RTL_EXPR_RTL (exp));
       free_temps_for_rtl_expr (exp);
       return RTL_EXPR_RTL (exp);
@@ -5216,7 +5199,10 @@ expand_expr (exp, target, tmode, modifier)
 
       else
        {
-         if (target == 0 || ! safe_from_p (target, exp))
+         /* Handle calls that pass values in multiple non-contiguous
+            locations.  The Irix 6 ABI has examples of this.  */
+         if (target == 0 || ! safe_from_p (target, exp)
+             || GET_CODE (target) == PARALLEL)
            {
              if (mode != BLKmode && ! TREE_ADDRESSABLE (exp))
                target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
@@ -5227,8 +5213,8 @@ expand_expr (exp, target, tmode, modifier)
          if (TREE_READONLY (exp))
            {
              if (GET_CODE (target) == MEM)
-               target = change_address (target, GET_MODE (target),
-                                        XEXP (target, 0));
+               target = copy_rtx (target);
+
              RTX_UNCHANGING_P (target) = 1;
            }
 
@@ -5439,8 +5425,46 @@ expand_expr (exp, target, tmode, modifier)
 
          for (elt = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); elt;
               elt = TREE_CHAIN (elt))
-           if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1))
-             return expand_expr (TREE_VALUE (elt), target, tmode, modifier);
+           if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1)
+               /* We can normally use the value of the field in the
+                  CONSTRUCTOR.  However, if this is a bitfield in
+                  an integral mode that we can fit in a HOST_WIDE_INT,
+                  we must mask only the number of bits in the bitfield,
+                  since this is done implicitly by the constructor.  If
+                  the bitfield does not meet either of those conditions,
+                  we can't do this optimization.  */
+               && (! DECL_BIT_FIELD (TREE_PURPOSE (elt))
+                   || ((GET_MODE_CLASS (DECL_MODE (TREE_PURPOSE (elt)))
+                        == MODE_INT)
+                       && (GET_MODE_BITSIZE (DECL_MODE (TREE_PURPOSE (elt)))
+                           <= HOST_BITS_PER_WIDE_INT))))
+             {
+               op0 =  expand_expr (TREE_VALUE (elt), target, tmode, modifier);
+               if (DECL_BIT_FIELD (TREE_PURPOSE (elt)))
+                 {
+                   int bitsize = DECL_FIELD_SIZE (TREE_PURPOSE (elt));
+                   enum machine_mode imode
+                     = TYPE_MODE (TREE_TYPE (TREE_PURPOSE (elt)));
+
+                   if (TREE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
+                     {
+                       op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1);
+                       op0 = expand_and (op0, op1, target);
+                     }
+                   else
+                     {
+                       tree count
+                         = build_int_2 (imode - bitsize, 0);
+
+                       op0 = expand_shift (LSHIFT_EXPR, imode, op0, count,
+                                           target, 0);
+                       op0 = expand_shift (RSHIFT_EXPR, imode, op0, count,
+                                           target, 0);
+                     }
+                 }
+
+               return op0;
+             }
        }
 
       {
@@ -5449,9 +5473,10 @@ expand_expr (exp, target, tmode, modifier)
        int bitpos;
        tree offset;
        int volatilep = 0;
-       tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
-                                       &mode1, &unsignedp, &volatilep);
        int alignment;
+       tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
+                                       &mode1, &unsignedp, &volatilep,
+                                       &alignment);
 
        /* If we got back the original object, something is wrong.  Perhaps
           we are evaluating an expression too early.  In any event, don't
@@ -5482,7 +5507,6 @@ expand_expr (exp, target, tmode, modifier)
              op0 = validize_mem (force_const_mem (mode, op0));
          }
 
-       alignment = TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT;
        if (offset != 0)
          {
            rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
@@ -5492,14 +5516,6 @@ expand_expr (exp, target, tmode, modifier)
            op0 = change_address (op0, VOIDmode,
                                  gen_rtx (PLUS, ptr_mode, XEXP (op0, 0),
                                           force_reg (ptr_mode, offset_rtx)));
-         /* If we have a variable offset, the known alignment
-            is only that of the innermost structure containing the field.
-            (Actually, we could sometimes do better by using the
-            size of an element of the innermost array, but no need.)  */
-         if (TREE_CODE (exp) == COMPONENT_REF
-             || TREE_CODE (exp) == BIT_FIELD_REF)
-           alignment = (TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0)))
-                        / BITS_PER_UNIT);
          }
 
        /* Don't forget about volatility even if this is a bitfield.  */
@@ -5612,10 +5628,13 @@ expand_expr (exp, target, tmode, modifier)
 
        MEM_IN_STRUCT_P (op0) = 1;
        MEM_VOLATILE_P (op0) |= volatilep;
-       if (mode == mode1 || mode1 == BLKmode || mode1 == tmode)
+       if (mode == mode1 || mode1 == BLKmode || mode1 == tmode
+           || modifier == EXPAND_CONST_ADDRESS
+           || modifier == EXPAND_INITIALIZER)
          return op0;
-       if (target == 0)
+       else if (target == 0)
          target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
+
        convert_move (target, op0, unsignedp);
        return target;
       }
@@ -5740,30 +5759,28 @@ expand_expr (exp, target, tmode, modifier)
        {
          RTL_EXPR_RTL (exp)
            = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
-         cleanups_this_call
-           = tree_cons (NULL_TREE, TREE_OPERAND (exp, 2), cleanups_this_call);
+         expand_decl_cleanup (NULL_TREE, TREE_OPERAND (exp, 2));
+
          /* That's it for this cleanup.  */
          TREE_OPERAND (exp, 2) = 0;
-         expand_eh_region_start ();
        }
       return RTL_EXPR_RTL (exp);
 
     case CLEANUP_POINT_EXPR:
       {
        extern int temp_slot_level;
-       tree old_cleanups = cleanups_this_call;
-       int old_temp_level = target_temp_slot_level;
-       push_temp_slots ();
+       /* Start a new binding layer that will keep track of all cleanup
+          actions to be performed.  */
+       expand_start_bindings (0);
+
        target_temp_slot_level = temp_slot_level;
+
        op0 = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
        /* If we're going to use this value, load it up now.  */
        if (! ignore)
          op0 = force_not_mem (op0);
-       expand_cleanups_to (old_cleanups);
        preserve_temp_slots (op0);
-       free_temp_slots ();
-       pop_temp_slots ();
-       target_temp_slot_level = old_temp_level;
+       expand_end_bindings (NULL_TREE, 0, 0);
       }
       return op0;
 
@@ -6439,18 +6456,32 @@ expand_expr (exp, target, tmode, modifier)
                          VOIDmode, 0);
 
     case COND_EXPR:
-      {
-       rtx flag = NULL_RTX;
-       tree left_cleanups = NULL_TREE;
-       tree right_cleanups = NULL_TREE;
-
-       /* Used to save a pointer to the place to put the setting of
-          the flag that indicates if this side of the conditional was
-          taken.  We backpatch the code, if we find out later that we
-          have any conditional cleanups that need to be performed.  */
-       rtx dest_right_flag = NULL_RTX;
-       rtx dest_left_flag = NULL_RTX;
+      /* If we would have a "singleton" (see below) were it not for a
+        conversion in each arm, bring that conversion back out.  */
+      if (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
+         && TREE_CODE (TREE_OPERAND (exp, 2)) == NOP_EXPR
+         && (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0))
+             == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 2), 0))))
+       {
+         tree true = TREE_OPERAND (TREE_OPERAND (exp, 1), 0);
+         tree false = TREE_OPERAND (TREE_OPERAND (exp, 2), 0);
+
+         if ((TREE_CODE_CLASS (TREE_CODE (true)) == '2'
+              && operand_equal_p (false, TREE_OPERAND (true, 0), 0))
+             || (TREE_CODE_CLASS (TREE_CODE (false)) == '2'
+                 && operand_equal_p (true, TREE_OPERAND (false, 0), 0))
+             || (TREE_CODE_CLASS (TREE_CODE (true)) == '1'
+                 && operand_equal_p (false, TREE_OPERAND (true, 0), 0))
+             || (TREE_CODE_CLASS (TREE_CODE (false)) == '1'
+                 && operand_equal_p (true, TREE_OPERAND (false, 0), 0)))
+           return expand_expr (build1 (NOP_EXPR, type,
+                                       build (COND_EXPR, TREE_TYPE (true),
+                                              TREE_OPERAND (exp, 0),
+                                              true, false)),
+                               target, tmode, modifier);
+       }
 
+      {
        /* Note that COND_EXPRs whose type is a structure or union
           are required to be constructed to contain assignments of
           a temporary variable, so that we can evaluate them here
@@ -6461,7 +6492,6 @@ expand_expr (exp, target, tmode, modifier)
 
        tree singleton = 0;
        tree binary_op = 0, unary_op = 0;
-       tree old_cleanups = cleanups_this_call;
 
        /* If this is (A ? 1 : 0) and A is a condition, just evaluate it and
           convert it to our mode, if necessary.  */
@@ -6486,11 +6516,11 @@ expand_expr (exp, target, tmode, modifier)
            return target;
          }
 
-       /* Check for X ? A + B : A.  If we have this, we can copy
-          A to the output and conditionally add B.  Similarly for unary
-          operations.  Don't do this if X has side-effects because
-          those side effects might affect A or B and the "?" operation is
-          a sequence point in ANSI.  (We test for side effects later.)  */
+       /* Check for X ? A + B : A.  If we have this, we can copy A to the
+          output and conditionally add B.  Similarly for unary operations.
+          Don't do this if X has side-effects because those side effects
+          might affect A or B and the "?" operation is a sequence point in
+          ANSI.  (operand_equal_p tests for side effects.)  */
 
        if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 1))) == '2'
            && operand_equal_p (TREE_OPERAND (exp, 2),
@@ -6530,16 +6560,17 @@ expand_expr (exp, target, tmode, modifier)
        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.  */
+       /* If we had X ? A + C : A, with C a constant power of 2, and we can
+          do the test of X as a store-flag operation, do this as
+          A + ((X != 0) << log C).  Similarly for other simple binary
+          operators.  Only do for C == 1 if BRANCH_COST is low.  */
        if (temp && singleton && binary_op
-           && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
            && (TREE_CODE (binary_op) == PLUS_EXPR
                || TREE_CODE (binary_op) == MINUS_EXPR
                || TREE_CODE (binary_op) == BIT_IOR_EXPR
                || TREE_CODE (binary_op) == BIT_XOR_EXPR)
-           && integer_onep (TREE_OPERAND (binary_op, 1))
+           && (BRANCH_COST >= 3 ? integer_pow2p (TREE_OPERAND (binary_op, 1))
+               : integer_onep (TREE_OPERAND (binary_op, 1)))
            && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
          {
            rtx result;
@@ -6564,6 +6595,15 @@ expand_expr (exp, target, tmode, modifier)
                                     ? temp : NULL_RTX),
                                    mode, BRANCH_COST <= 1);
 
+           if (result != 0 && ! integer_onep (TREE_OPERAND (binary_op, 1)))
+             result = expand_shift (LSHIFT_EXPR, mode, result,
+                                    build_int_2 (tree_log2
+                                                 (TREE_OPERAND
+                                                  (binary_op, 1)),
+                                                 0),
+                                    (safe_from_p (temp, singleton)
+                                     ? temp : NULL_RTX), 0);
+
            if (result)
              {
                op1 = expand_expr (singleton, NULL_RTX, VOIDmode, 0);
@@ -6579,7 +6619,6 @@ expand_expr (exp, target, tmode, modifier)
        NO_DEFER_POP;
        op0 = gen_label_rtx ();
 
-       flag = gen_reg_rtx (word_mode);
        if (singleton && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0)))
          {
            if (temp != 0)
@@ -6598,14 +6637,12 @@ expand_expr (exp, target, tmode, modifier)
            else
              expand_expr (singleton,
                           ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
-           dest_left_flag = get_last_insn ();
            if (singleton == TREE_OPERAND (exp, 1))
              jumpif (TREE_OPERAND (exp, 0), op0);
            else
              jumpifnot (TREE_OPERAND (exp, 0), op0);
 
-           /* Allows cleanups up to here.  */
-           old_cleanups = cleanups_this_call;
+           start_cleanup_deferal ();
            if (binary_op && temp == 0)
              /* Just touch the other operand.  */
              expand_expr (TREE_OPERAND (binary_op, 1),
@@ -6620,43 +6657,7 @@ expand_expr (exp, target, tmode, modifier)
                                  make_tree (type, temp)),
                          temp, 0);
            op1 = op0;
-           dest_right_flag = get_last_insn ();
-         }
-#if 0
-       /* This is now done in jump.c and is better done there because it
-          produces shorter register lifetimes.  */
-          
-       /* Check for both possibilities either constants or variables
-          in registers (but not the same as the target!).  If so, can
-          save branches by assigning one, branching, and assigning the
-          other.  */
-       else if (temp && GET_MODE (temp) != BLKmode
-                && (TREE_CONSTANT (TREE_OPERAND (exp, 1))
-                    || ((TREE_CODE (TREE_OPERAND (exp, 1)) == PARM_DECL
-                         || TREE_CODE (TREE_OPERAND (exp, 1)) == VAR_DECL)
-                        && DECL_RTL (TREE_OPERAND (exp, 1))
-                        && GET_CODE (DECL_RTL (TREE_OPERAND (exp, 1))) == REG
-                        && DECL_RTL (TREE_OPERAND (exp, 1)) != temp))
-                && (TREE_CONSTANT (TREE_OPERAND (exp, 2))
-                    || ((TREE_CODE (TREE_OPERAND (exp, 2)) == PARM_DECL
-                         || TREE_CODE (TREE_OPERAND (exp, 2)) == VAR_DECL)
-                        && DECL_RTL (TREE_OPERAND (exp, 2))
-                        && GET_CODE (DECL_RTL (TREE_OPERAND (exp, 2))) == REG
-                        && DECL_RTL (TREE_OPERAND (exp, 2)) != temp)))
-         {
-           if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
-             temp = gen_reg_rtx (mode);
-           store_expr (TREE_OPERAND (exp, 2), temp, 0);
-           dest_left_flag = get_last_insn ();
-           jumpifnot (TREE_OPERAND (exp, 0), op0);
-
-           /* Allows cleanups up to here.  */
-           old_cleanups = cleanups_this_call;
-           store_expr (TREE_OPERAND (exp, 1), temp, 0);
-           op1 = op0;
-           dest_right_flag = get_last_insn ();
          }
-#endif
        /* Check for A op 0 ? A : FOO and A op 0 ? FOO : A where OP is any
           comparison operator.  If we have one of these cases, set the
           output to A, branch on A (cse will merge these two references),
@@ -6672,14 +6673,11 @@ expand_expr (exp, target, tmode, modifier)
            if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
              temp = gen_reg_rtx (mode);
            store_expr (TREE_OPERAND (exp, 1), temp, 0);
-           dest_left_flag = get_last_insn ();
            jumpif (TREE_OPERAND (exp, 0), op0);
 
-           /* Allows cleanups up to here.  */
-           old_cleanups = cleanups_this_call;
+           start_cleanup_deferal ();
            store_expr (TREE_OPERAND (exp, 2), temp, 0);
            op1 = op0;
-           dest_right_flag = get_last_insn ();
          }
        else if (temp
                 && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<'
@@ -6692,102 +6690,42 @@ expand_expr (exp, target, tmode, modifier)
            if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
              temp = gen_reg_rtx (mode);
            store_expr (TREE_OPERAND (exp, 2), temp, 0);
-           dest_left_flag = get_last_insn ();
            jumpifnot (TREE_OPERAND (exp, 0), op0);
 
-           /* Allows cleanups up to here.  */
-           old_cleanups = cleanups_this_call;
+           start_cleanup_deferal ();
            store_expr (TREE_OPERAND (exp, 1), temp, 0);
            op1 = op0;
-           dest_right_flag = get_last_insn ();
          }
        else
          {
            op1 = gen_label_rtx ();
            jumpifnot (TREE_OPERAND (exp, 0), op0);
 
-           /* Allows cleanups up to here.  */
-           old_cleanups = cleanups_this_call;
+           start_cleanup_deferal ();
            if (temp != 0)
              store_expr (TREE_OPERAND (exp, 1), temp, 0);
            else
              expand_expr (TREE_OPERAND (exp, 1),
                           ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
-           dest_left_flag = get_last_insn ();
-
-           /* Handle conditional cleanups, if any.  */
-           left_cleanups = defer_cleanups_to (old_cleanups);
-
+           end_cleanup_deferal ();
            emit_queue ();
            emit_jump_insn (gen_jump (op1));
            emit_barrier ();
            emit_label (op0);
+           start_cleanup_deferal ();
            if (temp != 0)
              store_expr (TREE_OPERAND (exp, 2), temp, 0);
            else
              expand_expr (TREE_OPERAND (exp, 2),
                           ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
-           dest_right_flag = get_last_insn ();
          }
 
-       /* Handle conditional cleanups, if any.  */
-       right_cleanups = defer_cleanups_to (old_cleanups);
+       end_cleanup_deferal ();
 
        emit_queue ();
        emit_label (op1);
        OK_DEFER_POP;
 
-       /* Add back in, any conditional cleanups.  */
-       if (left_cleanups || right_cleanups)
-         {
-           tree new_cleanups;
-           tree cond;
-           rtx last;
-
-           /* Now that we know that a flag is needed, go back and add in the
-              setting of the flag.  */
-
-           /* Do the left side flag.  */
-           last = get_last_insn ();
-           /* Flag left cleanups as needed.  */
-           emit_move_insn (flag, const1_rtx);
-           /* ??? deprecated, use sequences instead.  */
-           reorder_insns (NEXT_INSN (last), get_last_insn (), dest_left_flag);
-
-           /* Do the right side flag.  */
-           last = get_last_insn ();
-           /* Flag left cleanups as needed.  */
-           emit_move_insn (flag, const0_rtx);
-           /* ??? deprecated, use sequences instead.  */
-           reorder_insns (NEXT_INSN (last), get_last_insn (), dest_right_flag);
-
-           /* All cleanups must be on the function_obstack.  */
-           push_obstacks_nochange ();
-           resume_temporary_allocation ();
-
-           /* convert flag, which is an rtx, into a tree.  */
-           cond = make_node (RTL_EXPR);
-           TREE_TYPE (cond) = integer_type_node;
-           RTL_EXPR_RTL (cond) = flag;
-           RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
-           cond = save_expr (cond);
-
-           if (! left_cleanups)
-             left_cleanups = integer_zero_node;
-           if (! right_cleanups)
-             right_cleanups = integer_zero_node;
-           new_cleanups = build (COND_EXPR, void_type_node,
-                                 truthvalue_conversion (cond),
-                                 left_cleanups, right_cleanups);
-           new_cleanups = fold (new_cleanups);
-
-           pop_obstacks ();
-
-           /* Now add in the conditionalized cleanups.  */
-           cleanups_this_call
-             = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
-           expand_eh_region_start ();
-         }
        return temp;
       }
 
@@ -6870,13 +6808,7 @@ expand_expr (exp, target, tmode, modifier)
 
        store_expr (exp1, target, 0);
 
-       if (cleanups)
-         {
-           cleanups_this_call = tree_cons (NULL_TREE,
-                                           cleanups,
-                                           cleanups_this_call);
-           expand_eh_region_start ();
-         }
+       expand_decl_cleanup (NULL_TREE, cleanups);
        
        return target;
       }
@@ -7159,6 +7091,33 @@ expand_expr (exp, target, tmode, modifier)
        return target;
       }
 
+    case TRY_CATCH_EXPR:
+      {
+       tree handler = TREE_OPERAND (exp, 1);
+
+       expand_eh_region_start ();
+
+       op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
+
+       expand_eh_region_end (handler);
+
+       return op0;
+      }
+
+    case POPDCC_EXPR:
+      {
+       rtx dcc = get_dynamic_cleanup_chain ();
+       emit_move_insn (dcc, validize_mem (gen_rtx (MEM, Pmode, dcc)));
+       return const0_rtx;
+      }
+
+    case POPDHC_EXPR:
+      {
+       rtx dhc = get_dynamic_handler_chain ();
+       emit_move_insn (dhc, validize_mem (gen_rtx (MEM, Pmode, dhc)));
+       return const0_rtx;
+      }
+
     case ERROR_MARK:
       op0 = CONST0_RTX (tmode);
       if (op0 != 0)
@@ -7924,6 +7883,174 @@ expand_builtin_return_addr (fndecl_code, count, tem)
 #endif
   return tem;
 }
+
+/* __builtin_setjmp is passed a pointer to an array of five words (not
+   all will be used on all machines).  It operates similarly to the C
+   library function of the same name, but is more efficient.  Much of
+   the code below (and for longjmp) is copied from the handling of
+   non-local gotos.
+
+   NOTE: This is intended for use by GNAT and the exception handling
+   scheme in the compiler and will only work in the method used by
+   them.  */
+
+rtx
+expand_builtin_setjmp (buf_addr, target)
+     rtx buf_addr;
+     rtx target;
+{
+  rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
+  enum machine_mode sa_mode = Pmode, value_mode;
+  rtx stack_save;
+  int old_inhibit_defer_pop = inhibit_defer_pop;
+  int return_pops
+    =  RETURN_POPS_ARGS (get_identifier ("__dummy"),
+                        build_function_type (void_type_node, NULL_TREE),
+                        0);
+  rtx next_arg_reg;
+  CUMULATIVE_ARGS args_so_far;
+  rtx op0;
+  int i;
+
+  value_mode = TYPE_MODE (integer_type_node);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+  buf_addr = convert_memory_address (Pmode, buf_addr);
+#endif
+
+  buf_addr = force_reg (Pmode, buf_addr);
+
+  if (target == 0 || GET_CODE (target) != REG
+      || REGNO (target) < FIRST_PSEUDO_REGISTER)
+    target = gen_reg_rtx (value_mode);
+
+  emit_queue ();
+
+  CONST_CALL_P (emit_note (NULL_PTR, NOTE_INSN_SETJMP)) = 1;
+  current_function_calls_setjmp = 1;
+
+  /* We store the frame pointer and the address of lab1 in the buffer
+     and use the rest of it for the stack save area, which is
+     machine-dependent.  */
+  emit_move_insn (gen_rtx (MEM, Pmode, buf_addr),
+                 virtual_stack_vars_rtx);
+  emit_move_insn
+    (validize_mem (gen_rtx (MEM, Pmode,
+                           plus_constant (buf_addr,
+                                          GET_MODE_SIZE (Pmode)))),
+     gen_rtx (LABEL_REF, Pmode, lab1));
+
+#ifdef HAVE_save_stack_nonlocal
+  if (HAVE_save_stack_nonlocal)
+    sa_mode = insn_operand_mode[(int) CODE_FOR_save_stack_nonlocal][0];
+#endif
+
+  stack_save = gen_rtx (MEM, sa_mode,
+                       plus_constant (buf_addr,
+                                      2 * GET_MODE_SIZE (Pmode)));
+  emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
+
+#ifdef HAVE_setjmp
+  if (HAVE_setjmp)
+    emit_insn (gen_setjmp ());
+#endif
+
+  /* Set TARGET to zero and branch around the other case.  */
+  emit_move_insn (target, const0_rtx);
+  emit_jump_insn (gen_jump (lab2));
+  emit_barrier ();
+  emit_label (lab1);
+
+  /* Note that setjmp clobbers FP when we get here, so we have to make
+     sure it's marked as used by this function.  */
+  emit_insn (gen_rtx (USE, VOIDmode, hard_frame_pointer_rtx));
+
+  /* Mark the static chain as clobbered here so life information
+     doesn't get messed up for it.  */
+  emit_insn (gen_rtx (CLOBBER, VOIDmode, static_chain_rtx));
+
+  /* Now put in the code to restore the frame pointer, and argument
+     pointer, if needed.  The code below is from expand_end_bindings
+     in stmt.c; see detailed documentation there.  */
+#ifdef HAVE_nonlocal_goto
+  if (! HAVE_nonlocal_goto)
+#endif
+    emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
+
+  /* Do we need to do something like:
+     
+     current_function_has_nonlocal_label = 1;
+
+     here?  It seems like we might have to, or some subset of that
+     functionality, but I am unsure.  (mrs) */
+
+#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+  if (fixed_regs[ARG_POINTER_REGNUM])
+    {
+#ifdef ELIMINABLE_REGS
+      static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
+
+      for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
+       if (elim_regs[i].from == ARG_POINTER_REGNUM
+           && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
+         break;
+
+      if (i == sizeof elim_regs / sizeof elim_regs [0])
+#endif
+       {
+         /* Now restore our arg pointer from the address at which it
+            was saved in our stack frame.
+            If there hasn't be space allocated for it yet, make
+            some now.  */
+         if (arg_pointer_save_area == 0)
+           arg_pointer_save_area
+             = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
+         emit_move_insn (virtual_incoming_args_rtx,
+                         copy_to_reg (arg_pointer_save_area));
+       }
+    }
+#endif
+
+#ifdef HAVE_nonlocal_goto_receiver
+  if (HAVE_nonlocal_goto_receiver)
+    emit_insn (gen_nonlocal_goto_receiver ());
+#endif
+  /* The static chain pointer contains the address of dummy function.
+     We need to call it here to handle some PIC cases of restoring a
+     global pointer.  Then return 1.  */
+  op0 = copy_to_mode_reg (Pmode, static_chain_rtx);
+
+  /* We can't actually call emit_library_call here, so do everything
+     it does, which isn't much for a libfunc with no args.  */
+  op0 = memory_address (FUNCTION_MODE, op0);
+
+  INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE,
+                       gen_rtx (SYMBOL_REF, Pmode, "__dummy"), 1);
+  next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1);
+
+#ifndef ACCUMULATE_OUTGOING_ARGS
+#ifdef HAVE_call_pop
+  if (HAVE_call_pop)
+    emit_call_insn (gen_call_pop (gen_rtx (MEM, FUNCTION_MODE, op0),
+                                 const0_rtx, next_arg_reg,
+                                 GEN_INT (return_pops)));
+  else
+#endif
+#endif
+
+#ifdef HAVE_call
+    if (HAVE_call)
+      emit_call_insn (gen_call (gen_rtx (MEM, FUNCTION_MODE, op0),
+                               const0_rtx, next_arg_reg, const0_rtx));
+    else
+#endif
+      abort ();
+
+  emit_move_insn (target, const1_rtx);
+  emit_label (lab2);
+  return target;
+}
+
 \f
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
@@ -8356,14 +8483,13 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       if (arglist == 0)
        /* Warning about missing arg was already issued.  */
        return const0_rtx;
-      else if (TREE_CODE (TREE_VALUE (arglist)) != INTEGER_CST)
-       {
-         error ("invalid arg to `__builtin_return_address'");
-         return const0_rtx;
-       }
-      else if (tree_int_cst_sgn (TREE_VALUE (arglist)) < 0)
+      else if (TREE_CODE (TREE_VALUE (arglist)) != INTEGER_CST
+              || tree_int_cst_sgn (TREE_VALUE (arglist)) < 0)
        {
-         error ("invalid arg to `__builtin_return_address'");
+         if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
+           error ("invalid arg to `__builtin_frame_address'");
+         else
+           error ("invalid arg to `__builtin_return_address'");
          return const0_rtx;
        }
       else
@@ -8762,15 +8888,6 @@ 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)
@@ -8779,146 +8896,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       {
        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;
+       return expand_builtin_setjmp (buf_addr, target);
       }
 
       /* __builtin_longjmp is passed a pointer to an array of five words
@@ -9797,68 +9775,6 @@ do_pending_stack_adjust ()
       pending_stack_adjust = 0;
     }
 }
-
-/* Defer the expansion all cleanups up to OLD_CLEANUPS.
-   Returns the cleanups to be performed.  */
-
-static tree
-defer_cleanups_to (old_cleanups)
-     tree old_cleanups;
-{
-  tree new_cleanups = NULL_TREE;
-  tree cleanups = cleanups_this_call;
-  tree last = NULL_TREE;
-
-  while (cleanups_this_call != old_cleanups)
-    {
-      expand_eh_region_end (TREE_VALUE (cleanups_this_call));
-      last = cleanups_this_call;
-      cleanups_this_call = TREE_CHAIN (cleanups_this_call);
-    }      
-
-  if (last)
-    {
-      /* Remove the list from the chain of cleanups.  */
-      TREE_CHAIN (last) = NULL_TREE;
-
-      /* reverse them so that we can build them in the right order.  */
-      cleanups = nreverse (cleanups);
-
-      /* All cleanups must be on the function_obstack.  */
-      push_obstacks_nochange ();
-      resume_temporary_allocation ();
-
-      while (cleanups)
-       {
-         if (new_cleanups)
-           new_cleanups = build (COMPOUND_EXPR, TREE_TYPE (new_cleanups),
-                                 TREE_VALUE (cleanups), new_cleanups);
-         else
-           new_cleanups = TREE_VALUE (cleanups);
-
-         cleanups = TREE_CHAIN (cleanups);
-       }
-
-      pop_obstacks ();
-    }
-
-  return new_cleanups;
-}
-
-/* Expand all cleanups up to OLD_CLEANUPS.
-   Needed here, and also for language-dependent calls.  */
-
-void
-expand_cleanups_to (old_cleanups)
-     tree old_cleanups;
-{
-  while (cleanups_this_call != old_cleanups)
-    {
-      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);
-    }
-}
 \f
 /* Expand conditional expressions.  */
 
@@ -10003,131 +9919,21 @@ do_jump (exp, if_false_label, if_true_label)
       break;
 
     case TRUTH_ANDIF_EXPR:
-      {
-       rtx seq1, seq2;
-       tree cleanups, old_cleanups;
-
-       if (if_false_label == 0)
-         if_false_label = drop_through_label = gen_label_rtx ();
-       start_sequence ();
-       do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
-       seq1 = get_insns ();
-       end_sequence ();
-
-       old_cleanups = cleanups_this_call;
-       start_sequence ();
-       do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
-       seq2 = get_insns ();
-       cleanups = defer_cleanups_to (old_cleanups);
-       end_sequence ();
-
-       if (cleanups)
-         {
-           rtx flag = gen_reg_rtx (word_mode);
-           tree new_cleanups;
-           tree cond;
-
-           /* Flag cleanups as not needed.  */
-           emit_move_insn (flag, const0_rtx);
-           emit_insns (seq1);
-
-           /* Flag cleanups as needed.  */
-           emit_move_insn (flag, const1_rtx);
-           emit_insns (seq2);
-
-           /* All cleanups must be on the function_obstack.  */
-           push_obstacks_nochange ();
-           resume_temporary_allocation ();
-
-           /* convert flag, which is an rtx, into a tree.  */
-           cond = make_node (RTL_EXPR);
-           TREE_TYPE (cond) = integer_type_node;
-           RTL_EXPR_RTL (cond) = flag;
-           RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
-           cond = save_expr (cond);
-
-           new_cleanups = build (COND_EXPR, void_type_node,
-                                 truthvalue_conversion (cond),
-                                 cleanups, integer_zero_node);
-           new_cleanups = fold (new_cleanups);
-
-           pop_obstacks ();
-
-           /* Now add in the conditionalized cleanups.  */
-           cleanups_this_call
-             = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
-           expand_eh_region_start ();
-         }
-       else
-         {
-           emit_insns (seq1);
-           emit_insns (seq2);
-         }
-      }
+      if (if_false_label == 0)
+       if_false_label = drop_through_label = gen_label_rtx ();
+      do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
+      start_cleanup_deferal ();
+      do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
+      end_cleanup_deferal ();
       break;
 
     case TRUTH_ORIF_EXPR:
-      {
-       rtx seq1, seq2;
-       tree cleanups, old_cleanups;
-
-       if (if_true_label == 0)
-         if_true_label = drop_through_label = gen_label_rtx ();
-       start_sequence ();
-       do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
-       seq1 = get_insns ();
-       end_sequence ();
-
-       old_cleanups = cleanups_this_call;
-       start_sequence ();
-       do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
-       seq2 = get_insns ();
-       cleanups = defer_cleanups_to (old_cleanups);
-       end_sequence ();
-
-       if (cleanups)
-         {
-           rtx flag = gen_reg_rtx (word_mode);
-           tree new_cleanups;
-           tree cond;
-
-           /* Flag cleanups as not needed.  */
-           emit_move_insn (flag, const0_rtx);
-           emit_insns (seq1);
-
-           /* Flag cleanups as needed.  */
-           emit_move_insn (flag, const1_rtx);
-           emit_insns (seq2);
-
-           /* All cleanups must be on the function_obstack.  */
-           push_obstacks_nochange ();
-           resume_temporary_allocation ();
-
-           /* convert flag, which is an rtx, into a tree.  */
-           cond = make_node (RTL_EXPR);
-           TREE_TYPE (cond) = integer_type_node;
-           RTL_EXPR_RTL (cond) = flag;
-           RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
-           cond = save_expr (cond);
-
-           new_cleanups = build (COND_EXPR, void_type_node,
-                                 truthvalue_conversion (cond),
-                                 cleanups, integer_zero_node);
-           new_cleanups = fold (new_cleanups);
-
-           pop_obstacks ();
-
-           /* Now add in the conditionalized cleanups.  */
-           cleanups_this_call
-             = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
-           expand_eh_region_start ();
-         }
-       else
-         {
-           emit_insns (seq1);
-           emit_insns (seq2);
-         }
-      }
+      if (if_true_label == 0)
+       if_true_label = drop_through_label = gen_label_rtx ();
+      do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
+      start_cleanup_deferal ();
+      do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
+      end_cleanup_deferal ();
       break;
 
     case COMPOUND_EXPR:
@@ -10150,11 +9956,13 @@ do_jump (exp, if_false_label, if_true_label)
        tree type;
        tree offset;
        int volatilep = 0;
+       int alignment;
 
        /* Get description of this reference.  We don't actually care
           about the underlying object here.  */
        get_inner_reference (exp, &bitsize, &bitpos, &offset,
-                            &mode, &unsignedp, &volatilep);
+                            &mode, &unsignedp, &volatilep,
+                            &alignment);
 
        type = type_for_size (bitsize, unsignedp);
        if (! SLOW_BYTE_ACCESS
@@ -10181,18 +9989,12 @@ 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 ();
+         start_cleanup_deferal ();
          /* Now the THEN-expression.  */
          do_jump (TREE_OPERAND (exp, 1),
                   if_false_label ? if_false_label : drop_through_label,
@@ -10200,71 +10002,12 @@ do_jump (exp, if_false_label, if_true_label)
          /* In case the do_jump just above never jumps.  */
          do_pending_stack_adjust ();
          emit_label (label1);
-         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);
-           }
+         end_cleanup_deferal ();
        }
       break;
 
@@ -11206,7 +10949,7 @@ bc_load_memory (type, decl)
     else
       abort ();
   else
-    /* See corresponding comment in bc_store_memory().  */
+    /* See corresponding comment in bc_store_memory.  */
     if (TYPE_MODE (type) == BLKmode
        || TYPE_MODE (type) == VOIDmode)
       return;
@@ -11882,7 +11625,7 @@ bc_load_bit_field (offset, size, unsignedp)
 
   /* Load: sign-extend if signed, else zero-extend */
   bc_emit_instruction (unsignedp ? zxloadBI : sxloadBI);
-}  
+}
 
 
 /* Adjust interpreter stack by NLEVELS.  Positive means drop NLEVELS