OSDN Git Service

2004-07-14 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / stmt.c
index 3d5da37..e9c6e5e 100644 (file)
@@ -124,7 +124,7 @@ static int cost_table_initialized;
    The position of an entry on `nesting_stack' is in its `depth' field.
 
    Each type of construct has its own individual stack.
-   For example, loops have `loop_stack'.  Each object points to the
+   For example, loops have `cond_stack'.  Each object points to the
    next object of the same type through the `next' field.
 
    Some constructs are visible to `break' exit-statements and others
@@ -142,7 +142,6 @@ struct nesting GTY(())
   rtx exit_label;
   enum nesting_desc {
     COND_NESTING,
-    LOOP_NESTING,
     BLOCK_NESTING,
     CASE_NESTING
   } desc;
@@ -159,50 +158,16 @@ struct nesting GTY(())
             This may be the end of the if or the next else/elseif.  */
          rtx next_label;
        } GTY ((tag ("COND_NESTING"))) cond;
-      /* For loops.  */
-      struct nesting_loop
-       {
-         /* Label at the top of the loop; place to loop back to.  */
-         rtx start_label;
-         /* Label at the end of the whole construct.  */
-         rtx end_label;
-         /* Label for `continue' statement to jump to;
-            this is in front of the stepper of the loop.  */
-         rtx continue_label;
-       } GTY ((tag ("LOOP_NESTING"))) loop;
       /* For variable binding contours.  */
       struct nesting_block
        {
          /* Sequence number of this binding contour within the function,
             in order of entry.  */
          int block_start_count;
-         /* Nonzero => value to restore stack to on exit.  */
-         rtx stack_level;
          /* The NOTE that starts this contour.
             Used by expand_goto to check whether the destination
             is within each contour or not.  */
          rtx first_insn;
-         /* Innermost containing binding contour that has a stack level.  */
-         struct nesting *innermost_stack_block;
-         /* List of cleanups to be run on exit from this contour.
-            This is a list of expressions to be evaluated.
-            The TREE_PURPOSE of each link is the ..._DECL node
-            which the cleanup pertains to.  */
-         tree cleanups;
-         /* List of cleanup-lists of blocks containing this block,
-            as they were at the locus where this block appears.
-            There is an element for each containing block,
-            ordered innermost containing block first.
-            The tail of this list can be 0,
-            if all remaining elements would be empty lists.
-            The element's TREE_VALUE is the cleanup-list of that block,
-            which may be null.  */
-         tree outer_cleanups;
-         /* Chain of labels defined inside this binding contour.
-            For contours that have stack levels or cleanups.  */
-         struct label_chain *label_chain;
-         /* Nonzero if this is associated with an EH region.  */
-         int exception_region;
          /* The saved target_temp_slot_level from our outer block.
             We may reset target_temp_slot_level to be the level of
             this block, if that is done, target_temp_slot_level
@@ -259,14 +224,10 @@ struct nesting GTY(())
 do { struct nesting *target = STACK;                   \
      struct nesting *this;                             \
      do { this = nesting_stack;                                \
-         if (loop_stack == this)                       \
-           loop_stack = loop_stack->next;              \
          if (cond_stack == this)                       \
            cond_stack = cond_stack->next;              \
          if (block_stack == this)                      \
            block_stack = block_stack->next;            \
-         if (stack_block_stack == this)                \
-           stack_block_stack = stack_block_stack->next; \
          if (case_stack == this)                       \
            case_stack = case_stack->next;              \
          nesting_depth = nesting_stack->depth - 1;     \
@@ -298,28 +259,6 @@ struct goto_fixup GTY(())
   /* Number of binding contours started in current function
      before the label reference.  */
   int block_start_count;
-  /* The outermost stack level that should be restored for this jump.
-     Each time a binding contour that resets the stack is exited,
-     if the target label is *not* yet defined, this slot is updated.  */
-  rtx stack_level;
-  /* List of lists of cleanup expressions to be run by this goto.
-     There is one element for each block that this goto is within.
-     The tail of this list can be 0,
-     if all remaining elements would be empty.
-     The TREE_VALUE contains the cleanup list of that block as of the
-     time this goto was seen.
-     The TREE_ADDRESSABLE flag is 1 for a block that has been exited.  */
-  tree cleanup_list_list;
-};
-
-/* Within any binding contour that must restore a stack level,
-   all labels are recorded with a chain of these structures.  */
-
-struct label_chain GTY(())
-{
-  /* Points to following fixup.  */
-  struct label_chain *next;
-  tree label;
 };
 
 struct stmt_status GTY(())
@@ -329,16 +268,9 @@ struct stmt_status GTY(())
 
   /* If any new stacks are added here, add them to POPSTACKS too.  */
 
-  /* Chain of all pending binding contours that restore stack levels
-     or have cleanups.  */
-  struct nesting * x_stack_block_stack;
-
   /* Chain of all pending conditional statements.  */
   struct nesting * x_cond_stack;
 
-  /* Chain of all pending loops.  */
-  struct nesting * x_loop_stack;
-
   /* Chain of all pending case or switch statements.  */
   struct nesting * x_case_stack;
 
@@ -352,16 +284,6 @@ struct stmt_status GTY(())
   /* Number of binding contours started so far in this function.  */
   int x_block_start_count;
 
-  /* Each time we expand an expression-statement,
-     record the expr's type and its RTL value here.  */
-  tree x_last_expr_type;
-  rtx x_last_expr_value;
-  rtx x_last_expr_alt_rtl;
-
-  /* Nonzero if within a ({...}) grouping, in which case we must
-     always compute a value for each expr-stmt in case it is the last one.  */
-  int x_expr_stmts_for_value;
-
   /* Location of last line-number note, whether we actually
      emitted it or not.  */
   location_t x_emit_locus;
@@ -370,41 +292,27 @@ struct stmt_status GTY(())
 };
 
 #define block_stack (cfun->stmt->x_block_stack)
-#define stack_block_stack (cfun->stmt->x_stack_block_stack)
 #define cond_stack (cfun->stmt->x_cond_stack)
-#define loop_stack (cfun->stmt->x_loop_stack)
 #define case_stack (cfun->stmt->x_case_stack)
 #define nesting_stack (cfun->stmt->x_nesting_stack)
 #define nesting_depth (cfun->stmt->x_nesting_depth)
 #define current_block_start_count (cfun->stmt->x_block_start_count)
-#define last_expr_type (cfun->stmt->x_last_expr_type)
-#define last_expr_value (cfun->stmt->x_last_expr_value)
-#define last_expr_alt_rtl (cfun->stmt->x_last_expr_alt_rtl)
-#define expr_stmts_for_value (cfun->stmt->x_expr_stmts_for_value)
 #define emit_locus (cfun->stmt->x_emit_locus)
 #define goto_fixup_chain (cfun->stmt->x_goto_fixup_chain)
 
 /* Nonzero if we are using EH to handle cleanups.  */
-static int using_eh_for_cleanups_p = 0;
+int using_eh_for_cleanups_p = 0;
 
 static int n_occurrences (int, const char *);
 static bool decl_conflicts_with_clobbers_p (tree, const HARD_REG_SET);
-static void expand_goto_internal (tree, rtx, rtx);
-static int expand_fixup (tree, rtx, rtx);
-static rtx expand_nl_handler_label (rtx, rtx);
 static void expand_nl_goto_receiver (void);
-static void expand_nl_goto_receivers (struct nesting *);
-static void fixup_gotos (struct nesting *, rtx, tree, rtx, int);
 static bool check_operand_nalternatives (tree, tree);
 static bool check_unique_operand_names (tree, tree);
 static char *resolve_operand_name_1 (char *, tree, tree);
-static void expand_null_return_1 (rtx);
+static void expand_null_return_1 (void);
 static enum br_predictor return_prediction (rtx);
 static rtx shift_return_value (rtx);
 static void expand_value_return (rtx);
-static int tail_recursion_args (tree, tree);
-static void expand_cleanups (tree, int, int);
-static void check_seenlabel (void);
 static void do_jump_if_equal (rtx, rtx, rtx, int);
 static int estimate_case_costs (case_node_ptr);
 static bool same_case_target_p (rtx, rtx);
@@ -454,8 +362,8 @@ emit_nop (void)
 
   last_insn = get_last_insn ();
   if (!optimize
-      && (GET_CODE (last_insn) == CODE_LABEL
-         || (GET_CODE (last_insn) == NOTE
+      && (LABEL_P (last_insn)
+         || (NOTE_P (last_insn)
              && prev_real_insn (last_insn) == 0)))
     emit_insn (gen_nop ());
 }
@@ -470,7 +378,12 @@ label_rtx (tree label)
     abort ();
 
   if (!DECL_RTL_SET_P (label))
-    SET_DECL_RTL (label, gen_label_rtx ());
+    {
+      rtx r = gen_label_rtx ();
+      SET_DECL_RTL (label, r);
+      if (FORCED_LABEL (label) || DECL_NONLOCAL (label))
+       LABEL_PRESERVE_P (r) = 1;
+    }
 
   return DECL_RTL (label);
 }
@@ -487,8 +400,7 @@ force_label_rtx (tree label)
   if (!function)
     abort ();
 
-  if (function != current_function_decl
-      && function != inline_function_decl)
+  if (function != current_function_decl)
     p = find_function_data (function);
   else
     p = cfun;
@@ -518,24 +430,8 @@ expand_computed_goto (tree exp)
 
   x = convert_memory_address (Pmode, x);
 
-  emit_queue ();
-
-  if (! cfun->computed_goto_common_label)
-    {
-      cfun->computed_goto_common_reg = copy_to_mode_reg (Pmode, x);
-      cfun->computed_goto_common_label = gen_label_rtx ();
-
-      do_pending_stack_adjust ();
-      emit_label (cfun->computed_goto_common_label);
-      emit_indirect_jump (cfun->computed_goto_common_reg);
-
-      current_function_has_computed_jump = 1;
-    }
-  else
-    {
-      emit_move_insn (cfun->computed_goto_common_reg, x);
-      emit_jump (cfun->computed_goto_common_label);
-    }
+  do_pending_stack_adjust ();
+  emit_indirect_jump (x);
 }
 \f
 /* Handle goto statements and the labels that they can go to.  */
@@ -554,40 +450,26 @@ expand_computed_goto (tree exp)
 void
 expand_label (tree label)
 {
-  struct label_chain *p;
+  rtx label_r = label_rtx (label);
 
   do_pending_stack_adjust ();
-  emit_label (label_rtx (label));
+  emit_label (label_r);
   if (DECL_NAME (label))
     LABEL_NAME (DECL_RTL (label)) = IDENTIFIER_POINTER (DECL_NAME (label));
 
-  if (stack_block_stack != 0)
+  if (DECL_NONLOCAL (label))
     {
-      p = ggc_alloc (sizeof (struct label_chain));
-      p->next = stack_block_stack->data.block.label_chain;
-      stack_block_stack->data.block.label_chain = p;
-      p->label = label;
+      expand_nl_goto_receiver ();
+      nonlocal_goto_handler_labels
+       = gen_rtx_EXPR_LIST (VOIDmode, label_r,
+                            nonlocal_goto_handler_labels);
     }
-}
 
-/* Declare that LABEL (a LABEL_DECL) may be used for nonlocal gotos
-   from nested functions.  */
-
-void
-declare_nonlocal_label (tree label)
-{
-  rtx slot = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
-
-  nonlocal_labels = tree_cons (NULL_TREE, label, nonlocal_labels);
-  LABEL_PRESERVE_P (label_rtx (label)) = 1;
-  if (nonlocal_goto_handler_slots == 0)
-    {
-      emit_stack_save (SAVE_NONLOCAL,
-                      &nonlocal_goto_stack_level,
-                      PREV_INSN (tail_recursion_reentry));
-    }
-  nonlocal_goto_handler_slots
-    = gen_rtx_EXPR_LIST (VOIDmode, slot, nonlocal_goto_handler_slots);
+  if (FORCED_LABEL (label))
+    forced_labels = gen_rtx_EXPR_LIST (VOIDmode, label_r, forced_labels);
+      
+  if (DECL_NONLOCAL (label) || FORCED_LABEL (label))
+    maybe_set_first_label_num (label_r);
 }
 
 /* Generate RTL code for a `goto' statement with target label LABEL.
@@ -597,485 +479,15 @@ declare_nonlocal_label (tree label)
 void
 expand_goto (tree label)
 {
-  tree context;
-
-  /* Check for a nonlocal goto to a containing function.  */
-  context = decl_function_context (label);
+#ifdef ENABLE_CHECKING
+  /* Check for a nonlocal goto to a containing function.  Should have
+     gotten translated to __builtin_nonlocal_goto.  */
+  tree context = decl_function_context (label);
   if (context != 0 && context != current_function_decl)
-    {
-      struct function *p = find_function_data (context);
-      rtx label_ref = gen_rtx_LABEL_REF (Pmode, label_rtx (label));
-      rtx handler_slot, static_chain, save_area, insn;
-      tree link;
-
-      /* Find the corresponding handler slot for this label.  */
-      handler_slot = p->x_nonlocal_goto_handler_slots;
-      for (link = p->x_nonlocal_labels; TREE_VALUE (link) != label;
-          link = TREE_CHAIN (link))
-       handler_slot = XEXP (handler_slot, 1);
-      handler_slot = XEXP (handler_slot, 0);
-
-      p->has_nonlocal_label = 1;
-      current_function_has_nonlocal_goto = 1;
-      LABEL_REF_NONLOCAL_P (label_ref) = 1;
-
-      /* Copy the rtl for the slots so that they won't be shared in
-        case the virtual stack vars register gets instantiated differently
-        in the parent than in the child.  */
-
-      static_chain = copy_to_reg (lookup_static_chain (label));
-
-      /* Get addr of containing function's current nonlocal goto handler,
-        which will do any cleanups and then jump to the label.  */
-      handler_slot = copy_to_reg (replace_rtx (copy_rtx (handler_slot),
-                                              virtual_stack_vars_rtx,
-                                              static_chain));
-
-      /* Get addr of containing function's nonlocal save area.  */
-      save_area = p->x_nonlocal_goto_stack_level;
-      if (save_area)
-       save_area = replace_rtx (copy_rtx (save_area),
-                                virtual_stack_vars_rtx, static_chain);
-
-#if HAVE_nonlocal_goto
-      if (HAVE_nonlocal_goto)
-       emit_insn (gen_nonlocal_goto (static_chain, handler_slot,
-                                     save_area, label_ref));
-      else
-#endif
-       {
-         emit_insn (gen_rtx_CLOBBER (VOIDmode,
-                                     gen_rtx_MEM (BLKmode,
-                                                  gen_rtx_SCRATCH (VOIDmode))));
-         emit_insn (gen_rtx_CLOBBER (VOIDmode,
-                                     gen_rtx_MEM (BLKmode,
-                                                  hard_frame_pointer_rtx)));
-
-         /* Restore frame pointer for containing function.
-            This sets the actual hard register used for the frame pointer
-            to the location of the function's incoming static chain info.
-            The non-local goto handler will then adjust it to contain the
-            proper value and reload the argument pointer, if needed.  */
-         emit_move_insn (hard_frame_pointer_rtx, static_chain);
-         emit_stack_restore (SAVE_NONLOCAL, save_area, NULL_RTX);
-
-         /* USE of hard_frame_pointer_rtx added for consistency;
-            not clear if really needed.  */
-         emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
-         emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
-         emit_indirect_jump (handler_slot);
-       }
-
-      /* Search backwards to the jump insn and mark it as a
-        non-local goto.  */
-      for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
-       {
-         if (GET_CODE (insn) == JUMP_INSN)
-           {
-             REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO,
-                                                 const0_rtx, REG_NOTES (insn));
-             break;
-           }
-         else if (GET_CODE (insn) == CALL_INSN)
-             break;
-       }
-    }
-  else
-    expand_goto_internal (label, label_rtx (label), NULL_RTX);
-}
-
-/* Generate RTL code for a `goto' statement with target label BODY.
-   LABEL should be a LABEL_REF.
-   LAST_INSN, if non-0, is the rtx we should consider as the last
-   insn emitted (for the purposes of cleaning up a return).  */
-
-static void
-expand_goto_internal (tree body, rtx label, rtx last_insn)
-{
-  struct nesting *block;
-  rtx stack_level = 0;
-
-  if (GET_CODE (label) != CODE_LABEL)
     abort ();
+#endif
 
-  /* If label has already been defined, we can tell now
-     whether and how we must alter the stack level.  */
-
-  if (PREV_INSN (label) != 0)
-    {
-      /* Find the innermost pending block that contains the label.
-        (Check containment by comparing insn-uids.)
-        Then restore the outermost stack level within that block,
-        and do cleanups of all blocks contained in it.  */
-      for (block = block_stack; block; block = block->next)
-       {
-         if (INSN_UID (block->data.block.first_insn) < INSN_UID (label))
-           break;
-         if (block->data.block.stack_level != 0)
-           stack_level = block->data.block.stack_level;
-         /* Execute the cleanups for blocks we are exiting.  */
-         if (block->data.block.cleanups != 0)
-           {
-             expand_cleanups (block->data.block.cleanups, 1, 1);
-             do_pending_stack_adjust ();
-           }
-       }
-
-      if (stack_level)
-       {
-         /* Ensure stack adjust isn't done by emit_jump, as this
-            would clobber the stack pointer.  This one should be
-            deleted as dead by flow.  */
-         clear_pending_stack_adjust ();
-         do_pending_stack_adjust ();
-
-         /* Don't do this adjust if it's to the end label and this function
-            is to return with a depressed stack pointer.  */
-         if (label == return_label
-             && (((TREE_CODE (TREE_TYPE (current_function_decl))
-                  == FUNCTION_TYPE)
-                  && (TYPE_RETURNS_STACK_DEPRESSED
-                      (TREE_TYPE (current_function_decl))))))
-           ;
-         else
-           emit_stack_restore (SAVE_BLOCK, stack_level, NULL_RTX);
-       }
-
-      if (body != 0 && DECL_TOO_LATE (body))
-       error ("jump to `%s' invalidly jumps into binding contour",
-              IDENTIFIER_POINTER (DECL_NAME (body)));
-    }
-  /* Label not yet defined: may need to put this goto
-     on the fixup list.  */
-  else if (! expand_fixup (body, label, last_insn))
-    {
-      /* No fixup needed.  Record that the label is the target
-        of at least one goto that has no fixup.  */
-      if (body != 0)
-       TREE_ADDRESSABLE (body) = 1;
-    }
-
-  emit_jump (label);
-}
-\f
-/* Generate if necessary a fixup for a goto
-   whose target label in tree structure (if any) is TREE_LABEL
-   and whose target in rtl is RTL_LABEL.
-
-   If LAST_INSN is nonzero, we pretend that the jump appears
-   after insn LAST_INSN instead of at the current point in the insn stream.
-
-   The fixup will be used later to insert insns just before the goto.
-   Those insns will restore the stack level as appropriate for the
-   target label, and will (in the case of C++) also invoke any object
-   destructors which have to be invoked when we exit the scopes which
-   are exited by the goto.
-
-   Value is nonzero if a fixup is made.  */
-
-static int
-expand_fixup (tree tree_label, rtx rtl_label, rtx last_insn)
-{
-  struct nesting *block, *end_block;
-
-  /* See if we can recognize which block the label will be output in.
-     This is possible in some very common cases.
-     If we succeed, set END_BLOCK to that block.
-     Otherwise, set it to 0.  */
-
-  if (cond_stack
-      && (rtl_label == cond_stack->data.cond.endif_label
-         || rtl_label == cond_stack->data.cond.next_label))
-    end_block = cond_stack;
-  /* If we are in a loop, recognize certain labels which
-     are likely targets.  This reduces the number of fixups
-     we need to create.  */
-  else if (loop_stack
-      && (rtl_label == loop_stack->data.loop.start_label
-         || rtl_label == loop_stack->data.loop.end_label
-         || rtl_label == loop_stack->data.loop.continue_label))
-    end_block = loop_stack;
-  else
-    end_block = 0;
-
-  /* Now set END_BLOCK to the binding level to which we will return.  */
-
-  if (end_block)
-    {
-      struct nesting *next_block = end_block->all;
-      block = block_stack;
-
-      /* First see if the END_BLOCK is inside the innermost binding level.
-        If so, then no cleanups or stack levels are relevant.  */
-      while (next_block && next_block != block)
-       next_block = next_block->all;
-
-      if (next_block)
-       return 0;
-
-      /* Otherwise, set END_BLOCK to the innermost binding level
-        which is outside the relevant control-structure nesting.  */
-      next_block = block_stack->next;
-      for (block = block_stack; block != end_block; block = block->all)
-       if (block == next_block)
-         next_block = next_block->next;
-      end_block = next_block;
-    }
-
-  /* Does any containing block have a stack level or cleanups?
-     If not, no fixup is needed, and that is the normal case
-     (the only case, for standard C).  */
-  for (block = block_stack; block != end_block; block = block->next)
-    if (block->data.block.stack_level != 0
-       || block->data.block.cleanups != 0)
-      break;
-
-  if (block != end_block)
-    {
-      /* Ok, a fixup is needed.  Add a fixup to the list of such.  */
-      struct goto_fixup *fixup = ggc_alloc (sizeof (struct goto_fixup));
-      /* In case an old stack level is restored, make sure that comes
-        after any pending stack adjust.  */
-      /* ?? If the fixup isn't to come at the present position,
-        doing the stack adjust here isn't useful.  Doing it with our
-        settings at that location isn't useful either.  Let's hope
-        someone does it!  */
-      if (last_insn == 0)
-       do_pending_stack_adjust ();
-      fixup->target = tree_label;
-      fixup->target_rtl = rtl_label;
-
-      /* Create a BLOCK node and a corresponding matched set of
-        NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes at
-        this point.  The notes will encapsulate any and all fixup
-        code which we might later insert at this point in the insn
-        stream.  Also, the BLOCK node will be the parent (i.e. the
-        `SUPERBLOCK') of any other BLOCK nodes which we might create
-        later on when we are expanding the fixup code.
-
-        Note that optimization passes (including expand_end_loop)
-        might move the *_BLOCK notes away, so we use a NOTE_INSN_DELETED
-        as a placeholder.  */
-
-      {
-       rtx original_before_jump
-         = last_insn ? last_insn : get_last_insn ();
-       rtx start;
-       rtx end;
-       tree block;
-
-       block = make_node (BLOCK);
-       TREE_USED (block) = 1;
-
-       if (!cfun->x_whole_function_mode_p)
-         lang_hooks.decls.insert_block (block);
-       else
-         {
-           BLOCK_CHAIN (block)
-             = BLOCK_CHAIN (DECL_INITIAL (current_function_decl));
-           BLOCK_CHAIN (DECL_INITIAL (current_function_decl))
-             = block;
-         }
-
-       start_sequence ();
-       start = emit_note (NOTE_INSN_BLOCK_BEG);
-       if (cfun->x_whole_function_mode_p)
-         NOTE_BLOCK (start) = block;
-       fixup->before_jump = emit_note (NOTE_INSN_DELETED);
-       end = emit_note (NOTE_INSN_BLOCK_END);
-       if (cfun->x_whole_function_mode_p)
-         NOTE_BLOCK (end) = block;
-       fixup->context = block;
-       end_sequence ();
-       emit_insn_after (start, original_before_jump);
-      }
-
-      fixup->block_start_count = current_block_start_count;
-      fixup->stack_level = 0;
-      fixup->cleanup_list_list
-       = ((block->data.block.outer_cleanups
-           || block->data.block.cleanups)
-          ? tree_cons (NULL_TREE, block->data.block.cleanups,
-                       block->data.block.outer_cleanups)
-          : 0);
-      fixup->next = goto_fixup_chain;
-      goto_fixup_chain = fixup;
-    }
-
-  return block != 0;
-}
-\f
-/* Expand any needed fixups in the outputmost binding level of the
-   function.  FIRST_INSN is the first insn in the function.  */
-
-void
-expand_fixups (rtx first_insn)
-{
-  fixup_gotos (NULL, NULL_RTX, NULL_TREE, first_insn, 0);
-}
-
-/* When exiting a binding contour, process all pending gotos requiring fixups.
-   THISBLOCK is the structure that describes the block being exited.
-   STACK_LEVEL is the rtx for the stack level to restore exiting this contour.
-   CLEANUP_LIST is a list of expressions to evaluate on exiting this contour.
-   FIRST_INSN is the insn that began this contour.
-
-   Gotos that jump out of this contour must restore the
-   stack level and do the cleanups before actually jumping.
-
-   DONT_JUMP_IN positive means report error if there is a jump into this
-   contour from before the beginning of the contour.  This is also done if
-   STACK_LEVEL is nonzero unless DONT_JUMP_IN is negative.  */
-
-static void
-fixup_gotos (struct nesting *thisblock, rtx stack_level,
-            tree cleanup_list, rtx first_insn, int dont_jump_in)
-{
-  struct goto_fixup *f, *prev;
-
-  /* F is the fixup we are considering; PREV is the previous one.  */
-  /* We run this loop in two passes so that cleanups of exited blocks
-     are run first, and blocks that are exited are marked so
-     afterwards.  */
-
-  for (prev = 0, f = goto_fixup_chain; f; prev = f, f = f->next)
-    {
-      /* Test for a fixup that is inactive because it is already handled.  */
-      if (f->before_jump == 0)
-       {
-         /* Delete inactive fixup from the chain, if that is easy to do.  */
-         if (prev != 0)
-           prev->next = f->next;
-       }
-      /* Has this fixup's target label been defined?
-        If so, we can finalize it.  */
-      else if (PREV_INSN (f->target_rtl) != 0)
-       {
-         rtx cleanup_insns;
-
-         /* If this fixup jumped into this contour from before the beginning
-            of this contour, report an error.   This code used to use
-            the first non-label insn after f->target_rtl, but that's
-            wrong since such can be added, by things like put_var_into_stack
-            and have INSN_UIDs that are out of the range of the block.  */
-         /* ??? Bug: this does not detect jumping in through intermediate
-            blocks that have stack levels or cleanups.
-            It detects only a problem with the innermost block
-            around the label.  */
-         if (f->target != 0
-             && (dont_jump_in > 0 || (dont_jump_in == 0 && stack_level)
-                 || cleanup_list)
-             && INSN_UID (first_insn) < INSN_UID (f->target_rtl)
-             && INSN_UID (first_insn) > INSN_UID (f->before_jump)
-             && ! DECL_ERROR_ISSUED (f->target))
-           {
-             error ("%Jlabel '%D' used before containing binding contour",
-                    f->target, f->target);
-             /* Prevent multiple errors for one label.  */
-             DECL_ERROR_ISSUED (f->target) = 1;
-           }
-
-         /* We will expand the cleanups into a sequence of their own and
-            then later on we will attach this new sequence to the insn
-            stream just ahead of the actual jump insn.  */
-
-         start_sequence ();
-
-         /* Temporarily restore the lexical context where we will
-            logically be inserting the fixup code.  We do this for the
-            sake of getting the debugging information right.  */
-
-         lang_hooks.decls.pushlevel (0);
-         lang_hooks.decls.set_block (f->context);
-
-         /* Expand the cleanups for blocks this jump exits.  */
-         if (f->cleanup_list_list)
-           {
-             tree lists;
-             for (lists = f->cleanup_list_list; lists; lists = TREE_CHAIN (lists))
-               /* Marked elements correspond to blocks that have been closed.
-                  Do their cleanups.  */
-               if (TREE_ADDRESSABLE (lists)
-                   && TREE_VALUE (lists) != 0)
-                 {
-                   expand_cleanups (TREE_VALUE (lists), 1, 1);
-                   /* Pop any pushes done in the cleanups,
-                      in case function is about to return.  */
-                   do_pending_stack_adjust ();
-                 }
-           }
-
-         /* Restore stack level for the biggest contour that this
-            jump jumps out of.  */
-         if (f->stack_level
-             && ! (f->target_rtl == return_label
-                   && ((TREE_CODE (TREE_TYPE (current_function_decl))
-                        == FUNCTION_TYPE)
-                       && (TYPE_RETURNS_STACK_DEPRESSED
-                           (TREE_TYPE (current_function_decl))))))
-           emit_stack_restore (SAVE_BLOCK, f->stack_level, f->before_jump);
-
-         /* Finish up the sequence containing the insns which implement the
-            necessary cleanups, and then attach that whole sequence to the
-            insn stream just ahead of the actual jump insn.  Attaching it
-            at that point insures that any cleanups which are in fact
-            implicit C++ object destructions (which must be executed upon
-            leaving the block) appear (to the debugger) to be taking place
-            in an area of the generated code where the object(s) being
-            destructed are still "in scope".  */
-
-         cleanup_insns = get_insns ();
-         lang_hooks.decls.poplevel (1, 0, 0);
-
-         end_sequence ();
-         emit_insn_after (cleanup_insns, f->before_jump);
-
-         f->before_jump = 0;
-       }
-    }
-
-  /* For any still-undefined labels, do the cleanups for this block now.
-     We must do this now since items in the cleanup list may go out
-     of scope when the block ends.  */
-  for (prev = 0, f = goto_fixup_chain; f; prev = f, f = f->next)
-    if (f->before_jump != 0
-       && PREV_INSN (f->target_rtl) == 0
-       /* Label has still not appeared.  If we are exiting a block with
-          a stack level to restore, that started before the fixup,
-          mark this stack level as needing restoration
-          when the fixup is later finalized.  */
-       && thisblock != 0
-       /* Note: if THISBLOCK == 0 and we have a label that hasn't appeared, it
-          means the label is undefined.  That's erroneous, but possible.  */
-       && (thisblock->data.block.block_start_count
-           <= f->block_start_count))
-      {
-       tree lists = f->cleanup_list_list;
-       rtx cleanup_insns;
-
-       for (; lists; lists = TREE_CHAIN (lists))
-         /* If the following elt. corresponds to our containing block
-            then the elt. must be for this block.  */
-         if (TREE_CHAIN (lists) == thisblock->data.block.outer_cleanups)
-           {
-             start_sequence ();
-             lang_hooks.decls.pushlevel (0);
-             lang_hooks.decls.set_block (f->context);
-             expand_cleanups (TREE_VALUE (lists), 1, 1);
-             do_pending_stack_adjust ();
-             cleanup_insns = get_insns ();
-             lang_hooks.decls.poplevel (1, 0, 0);
-             end_sequence ();
-             if (cleanup_insns != 0)
-               f->before_jump
-                 = emit_insn_after (cleanup_insns, f->before_jump);
-
-             f->cleanup_list_list = TREE_CHAIN (lists);
-           }
-
-       if (stack_level)
-         f->stack_level = stack_level;
-      }
+  emit_jump (label_rtx (label));
 }
 \f
 /* Return the number of times character C occurs in string S.  */
@@ -1106,8 +518,6 @@ expand_asm (tree string, int vol)
   MEM_VOLATILE_P (body) = vol;
 
   emit_insn (body);
-
-  clear_last_expr ();
 }
 
 /* Parse the output constraint pointed to by *CONSTRAINT_P.  It is the
@@ -1251,9 +661,6 @@ parse_output_constraint (const char **constraint_p, int operand_num,
        break;
       }
 
-  if (*is_inout && !*allows_reg)
-    warning ("read-write constraint does not allow a register");
-
   return true;
 }
 
@@ -1393,6 +800,33 @@ parse_input_constraint (const char **constraint_p, int input_num,
   return true;
 }
 
+/* INPUT is one of the input operands from EXPR, an ASM_EXPR.  Returns true
+   if it is an operand which must be passed in memory (i.e. an "m"
+   constraint), false otherwise.  */
+
+bool
+asm_op_is_mem_input (tree input, tree expr)
+{
+  const char *constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (input)));
+  tree outputs = ASM_OUTPUTS (expr);
+  int noutputs = list_length (outputs);
+  const char **constraints
+    = (const char **) alloca ((noutputs) * sizeof (const char *));
+  int i = 0;
+  bool allows_mem, allows_reg;
+  tree t;
+
+  /* Collect output constraints.  */
+  for (t = outputs; t ; t = TREE_CHAIN (t), i++)
+    constraints[i] = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+
+  /* We pass 0 for input_num, ninputs and ninout; they are only used for
+     error checking which will be done at expand time.  */
+  parse_input_constraint (&constraint, 0, 0, noutputs, 0, constraints,
+                         &allows_mem, &allows_reg);
+  return (!allows_reg && allows_mem);
+}
+
 /* Check for overlap between registers marked in CLOBBERED_REGS and
    anything inappropriate in DECL.  Emit error and return TRUE for error,
    FALSE for ok.  */
@@ -1520,8 +954,6 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
        }
     }
 
-  clear_last_expr ();
-
   /* First pass over inputs and outputs checks validity and sets
      mark_addressable if needed.  */
 
@@ -1550,7 +982,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
          && (allows_mem
              || is_inout
              || (DECL_P (val)
-                 && GET_CODE (DECL_RTL (val)) == REG
+                 && REG_P (DECL_RTL (val))
                  && GET_MODE (DECL_RTL (val)) != TYPE_MODE (type))))
        lang_hooks.mark_addressable (val);
 
@@ -1612,22 +1044,22 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
       if ((TREE_CODE (val) == INDIRECT_REF
           && allows_mem)
          || (DECL_P (val)
-             && (allows_mem || GET_CODE (DECL_RTL (val)) == REG)
-             && ! (GET_CODE (DECL_RTL (val)) == REG
+             && (allows_mem || REG_P (DECL_RTL (val)))
+             && ! (REG_P (DECL_RTL (val))
                    && GET_MODE (DECL_RTL (val)) != TYPE_MODE (type)))
          || ! allows_reg
          || is_inout)
        {
          op = expand_expr (val, NULL_RTX, VOIDmode, EXPAND_WRITE);
-         if (GET_CODE (op) == MEM)
+         if (MEM_P (op))
            op = validize_mem (op);
 
-         if (! allows_reg && GET_CODE (op) != MEM)
+         if (! allows_reg && !MEM_P (op))
            error ("output number %d not directly addressable", i);
-         if ((! allows_mem && GET_CODE (op) == MEM)
+         if ((! allows_mem && MEM_P (op))
              || GET_CODE (op) == CONCAT)
            {
-             real_output_rtx[i] = protect_from_queue (op, 1);
+             real_output_rtx[i] = op;
              op = gen_reg_rtx (GET_MODE (op));
              if (is_inout)
                emit_move_insn (op, real_output_rtx[i]);
@@ -1663,7 +1095,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
                                : GET_MODE (output_rtx[0])),
                               TREE_STRING_POINTER (string),
                               empty_string, 0, argvec, constraintvec,
-                              locus.file, locus.line);
+                              locus);
 
   MEM_VOLATILE_P (body) = vol;
 
@@ -1693,7 +1125,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
       /* Never pass a CONCAT to an ASM.  */
       if (GET_CODE (op) == CONCAT)
        op = force_reg (GET_MODE (op), op);
-      else if (GET_CODE (op) == MEM)
+      else if (MEM_P (op))
        op = validize_mem (op);
 
       if (asm_operand_ok (op, constraint) <= 0)
@@ -1703,7 +1135,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
          else if (!allows_mem)
            warning ("asm operand %d probably doesn't match constraints",
                     i + noutputs);
-         else if (GET_CODE (op) == MEM)
+         else if (MEM_P (op))
            {
              /* We won't recognize either volatile memory or memory
                 with a queued address as available a memory_operand
@@ -1722,9 +1154,8 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
                  else
                    op = force_reg (TYPE_MODE (type), op);
                }
-             if (GET_CODE (op) == REG
+             if (REG_P (op)
                  || GET_CODE (op) == SUBREG
-                 || GET_CODE (op) == ADDRESSOF
                  || GET_CODE (op) == CONCAT)
                {
                  tree qual_type = build_qualified_type (type,
@@ -1753,13 +1184,6 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
 
   generating_concat_p = 0;
 
-  for (i = 0; i < ninputs - ninout; i++)
-    ASM_OPERANDS_INPUT (body, i)
-      = protect_from_queue (ASM_OPERANDS_INPUT (body, i), 0);
-
-  for (i = 0; i < noutputs; i++)
-    output_rtx[i] = protect_from_queue (output_rtx[i], 1);
-
   /* For in-out operands, copy output rtx to input rtx.  */
   for (i = 0; i < ninout; i++)
     {
@@ -1813,7 +1237,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
                           (GET_MODE (output_rtx[i]),
                            TREE_STRING_POINTER (string),
                            constraints[i], i, argvec, constraintvec,
-                           locus.file, locus.line));
+                           locus));
 
          MEM_VOLATILE_P (SET_SRC (XVECEXP (body, 0, i))) = vol;
        }
@@ -1889,6 +1313,49 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
   free_temp_slots ();
 }
 
+void
+expand_asm_expr (tree exp)
+{
+  int noutputs, i;
+  tree outputs, tail;
+  tree *o;
+
+  if (ASM_INPUT_P (exp))
+    {
+      expand_asm (ASM_STRING (exp), ASM_VOLATILE_P (exp));
+      return;
+    }
+
+  outputs = ASM_OUTPUTS (exp);
+  noutputs = list_length (outputs);
+  /* o[I] is the place that output number I should be written.  */
+  o = (tree *) alloca (noutputs * sizeof (tree));
+
+  /* Record the contents of OUTPUTS before it is modified.  */
+  for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
+    o[i] = TREE_VALUE (tail);
+
+  /* Generate the ASM_OPERANDS insn; store into the TREE_VALUEs of
+     OUTPUTS some trees for where the values were actually stored.  */
+  expand_asm_operands (ASM_STRING (exp), outputs, ASM_INPUTS (exp),
+                      ASM_CLOBBERS (exp), ASM_VOLATILE_P (exp),
+                      input_location);
+
+  /* Copy all the intermediate outputs into the specified outputs.  */
+  for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
+    {
+      if (o[i] != TREE_VALUE (tail))
+       {
+         expand_assignment (o[i], TREE_VALUE (tail), 0);
+         free_temp_slots ();
+
+         /* Restore the original value so that it's correct the next
+            time we expand this function.  */
+         TREE_VALUE (tail) = o[i];
+       }
+    }
+}
+
 /* A subroutine of expand_asm_operands.  Check that all operands have
    the same number of alternatives.  Return true if so.  */
 
@@ -2114,61 +1581,20 @@ resolve_operand_name_1 (char *p, tree outputs, tree inputs)
   return p;
 }
 \f
-/* Generate RTL to evaluate the expression EXP
-   and remember it in case this is the VALUE in a ({... VALUE; }) constr.
-   Provided just for backward-compatibility.  expand_expr_stmt_value()
-   should be used for new code.  */
+/* Generate RTL to evaluate the expression EXP.  */
 
 void
 expand_expr_stmt (tree exp)
 {
-  expand_expr_stmt_value (exp, -1, 1);
-}
-
-/* Generate RTL to evaluate the expression EXP.  WANT_VALUE tells
-   whether to (1) save the value of the expression, (0) discard it or
-   (-1) use expr_stmts_for_value to tell.  The use of -1 is
-   deprecated, and retained only for backward compatibility.  */
-
-void
-expand_expr_stmt_value (tree exp, int want_value, int maybe_last)
-{
   rtx value;
   tree type;
-  rtx alt_rtl = NULL;
-
-  if (want_value == -1)
-    want_value = expr_stmts_for_value != 0;
-
-  /* If -Wextra, warn about statements with no side effects,
-     except for an explicit cast to void (e.g. for assert()), and
-     except for last statement in ({...}) where they may be useful.  */
-  if (! want_value
-      && (expr_stmts_for_value == 0 || ! maybe_last)
-      && exp != error_mark_node
-      && warn_unused_value)
-    {
-      if (TREE_SIDE_EFFECTS (exp))
-       warn_if_unused_value (exp);
-      else if (!VOID_TYPE_P (TREE_TYPE (exp)))
-       warning ("%Hstatement with no effect", &emit_locus);
-    }
 
-  /* If EXP is of function type and we are expanding statements for
-     value, convert it to pointer-to-function.  */
-  if (want_value && TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE)
-    exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp);
-
-  /* The call to `expand_expr' could cause last_expr_type and
-     last_expr_value to get reset.  Therefore, we set last_expr_value
-     and last_expr_type *after* calling expand_expr.  */
-  value = expand_expr_real (exp, want_value ? NULL_RTX : const0_rtx,
-                           VOIDmode, 0, &alt_rtl);
+  value = expand_expr (exp, const0_rtx, VOIDmode, 0);
   type = TREE_TYPE (exp);
 
   /* If all we do is reference a volatile value in memory,
      copy it to a register to be sure it is actually touched.  */
-  if (value && GET_CODE (value) == MEM && TREE_THIS_VOLATILE (exp))
+  if (value && MEM_P (value) && TREE_THIS_VOLATILE (exp))
     {
       if (TYPE_MODE (type) == VOIDmode)
        ;
@@ -2187,31 +1613,18 @@ expand_expr_stmt_value (tree exp, int want_value, int maybe_last)
        }
     }
 
-  /* If this expression is part of a ({...}) and is in memory, we may have
-     to preserve temporaries.  */
-  preserve_temp_slots (value);
-
-  /* Free any temporaries used to evaluate this expression.  Any temporary
-     used as a result of this expression will already have been preserved
-     above.  */
+  /* Free any temporaries used to evaluate this expression.  */
   free_temp_slots ();
-
-  if (want_value)
-    {
-      last_expr_value = value;
-      last_expr_alt_rtl = alt_rtl;
-      last_expr_type = type;
-    }
-
-  emit_queue ();
 }
 
 /* Warn if EXP contains any computations whose results are not used.
-   Return 1 if a warning is printed; 0 otherwise.  */
+   Return 1 if a warning is printed; 0 otherwise.  LOCUS is the 
+   (potential) location of the expression.  */
 
 int
-warn_if_unused_value (tree exp)
+warn_if_unused_value (tree exp, location_t locus)
 {
+ restart:
   if (TREE_USED (exp))
     return 0;
 
@@ -2221,6 +1634,9 @@ warn_if_unused_value (tree exp)
   if (VOID_TYPE_P (TREE_TYPE (exp)))
     return 0;
 
+  if (EXPR_LOCUS (exp))
+    locus = *EXPR_LOCUS (exp);
+
   switch (TREE_CODE (exp))
     {
     case PREINCREMENT_EXPR:
@@ -2231,7 +1647,6 @@ warn_if_unused_value (tree exp)
     case INIT_EXPR:
     case TARGET_EXPR:
     case CALL_EXPR:
-    case RTL_EXPR:
     case TRY_CATCH_EXPR:
     case WITH_CLEANUP_EXPR:
     case EXIT_EXPR:
@@ -2239,31 +1654,35 @@ warn_if_unused_value (tree exp)
 
     case BIND_EXPR:
       /* For a binding, warn if no side effect within it.  */
-      return warn_if_unused_value (TREE_OPERAND (exp, 1));
+      exp = BIND_EXPR_BODY (exp);
+      goto restart;
 
     case SAVE_EXPR:
-      return warn_if_unused_value (TREE_OPERAND (exp, 1));
+      exp = TREE_OPERAND (exp, 0);
+      goto restart;
 
     case TRUTH_ORIF_EXPR:
     case TRUTH_ANDIF_EXPR:
       /* In && or ||, warn if 2nd operand has no side effect.  */
-      return warn_if_unused_value (TREE_OPERAND (exp, 1));
+      exp = TREE_OPERAND (exp, 1);
+      goto restart;
 
     case COMPOUND_EXPR:
-      if (TREE_NO_UNUSED_WARNING (exp))
+      if (TREE_NO_WARNING (exp))
        return 0;
-      if (warn_if_unused_value (TREE_OPERAND (exp, 0)))
+      if (warn_if_unused_value (TREE_OPERAND (exp, 0), locus))
        return 1;
       /* Let people do `(foo (), 0)' without a warning.  */
       if (TREE_CONSTANT (TREE_OPERAND (exp, 1)))
        return 0;
-      return warn_if_unused_value (TREE_OPERAND (exp, 1));
+      exp = TREE_OPERAND (exp, 1);
+      goto restart;
 
     case NOP_EXPR:
     case CONVERT_EXPR:
     case NON_LVALUE_EXPR:
       /* Don't warn about conversions not explicit in the user's program.  */
-      if (TREE_NO_UNUSED_WARNING (exp))
+      if (TREE_NO_WARNING (exp))
        return 0;
       /* Assignment to a cast usually results in a cast of a modify.
         Don't complain about that.  There can be an arbitrary number of
@@ -2285,7 +1704,10 @@ warn_if_unused_value (tree exp)
       /* Don't warn about automatic dereferencing of references, since
         the user cannot control it.  */
       if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE)
-       return warn_if_unused_value (TREE_OPERAND (exp, 0));
+       {
+         exp = TREE_OPERAND (exp, 0);
+         goto restart;
+       }
       /* Fall through.  */
 
     default:
@@ -2307,94 +1729,10 @@ warn_if_unused_value (tree exp)
       if (TREE_SIDE_EFFECTS (exp))
        return 0;
 
-      warning ("%Hvalue computed is not used", &emit_locus);
+      warning ("%Hvalue computed is not used", &locus);
       return 1;
     }
 }
-
-/* Clear out the memory of the last expression evaluated.  */
-
-void
-clear_last_expr (void)
-{
-  last_expr_type = NULL_TREE;
-  last_expr_value = NULL_RTX;
-  last_expr_alt_rtl = NULL_RTX;
-}
-
-/* Begin a statement-expression, i.e., a series of statements which
-   may return a value.  Return the RTL_EXPR for this statement expr.
-   The caller must save that value and pass it to
-   expand_end_stmt_expr.  If HAS_SCOPE is nonzero, temporaries created
-   in the statement-expression are deallocated at the end of the
-   expression.  */
-
-tree
-expand_start_stmt_expr (int has_scope)
-{
-  tree t;
-
-  /* Make the RTL_EXPR node temporary, not momentary,
-     so that rtl_expr_chain doesn't become garbage.  */
-  t = make_node (RTL_EXPR);
-  do_pending_stack_adjust ();
-  if (has_scope)
-    start_sequence_for_rtl_expr (t);
-  else
-    start_sequence ();
-  NO_DEFER_POP;
-  expr_stmts_for_value++;
-  return t;
-}
-
-/* Restore the previous state at the end of a statement that returns a value.
-   Returns a tree node representing the statement's value and the
-   insns to compute the value.
-
-   The nodes of that expression have been freed by now, so we cannot use them.
-   But we don't want to do that anyway; the expression has already been
-   evaluated and now we just want to use the value.  So generate a RTL_EXPR
-   with the proper type and RTL value.
-
-   If the last substatement was not an expression,
-   return something with type `void'.  */
-
-tree
-expand_end_stmt_expr (tree t)
-{
-  OK_DEFER_POP;
-
-  if (! last_expr_value || ! last_expr_type)
-    {
-      last_expr_value = const0_rtx;
-      last_expr_alt_rtl = NULL_RTX;
-      last_expr_type = void_type_node;
-    }
-  else if (GET_CODE (last_expr_value) != REG && ! CONSTANT_P (last_expr_value))
-    /* Remove any possible QUEUED.  */
-    last_expr_value = protect_from_queue (last_expr_value, 0);
-
-  emit_queue ();
-
-  TREE_TYPE (t) = last_expr_type;
-  RTL_EXPR_RTL (t) = last_expr_value;
-  RTL_EXPR_ALT_RTL (t) = last_expr_alt_rtl;
-  RTL_EXPR_SEQUENCE (t) = get_insns ();
-
-  rtl_expr_chain = tree_cons (NULL_TREE, t, rtl_expr_chain);
-
-  end_sequence ();
-
-  /* Don't consider deleting this expr or containing exprs at tree level.  */
-  TREE_SIDE_EFFECTS (t) = 1;
-  /* Propagate volatility of the actual RTL expr.  */
-  TREE_THIS_VOLATILE (t) = volatile_refs_p (last_expr_value);
-
-  clear_last_expr ();
-  expr_stmts_for_value--;
-
-  return t;
-}
 \f
 /* Generate RTL for the start of an if-then.  COND is the expression
    whose truth should be tested.
@@ -2478,403 +1816,24 @@ expand_end_cond (void)
     emit_label (thiscond->data.cond.endif_label);
 
   POPSTACK (cond_stack);
-  clear_last_expr ();
 }
 \f
-/* Generate RTL for the start of a loop.  EXIT_FLAG is nonzero if this
-   loop should be exited by `exit_something'.  This is a loop for which
-   `expand_continue' will jump to the top of the loop.
-
-   Make an entry on loop_stack to record the labels associated with
-   this loop.  */
-
-struct nesting *
-expand_start_loop (int exit_flag)
-{
-  struct nesting *thisloop = ALLOC_NESTING ();
-
-  /* Make an entry on loop_stack for the loop we are entering.  */
-
-  thisloop->desc = LOOP_NESTING;
-  thisloop->next = loop_stack;
-  thisloop->all = nesting_stack;
-  thisloop->depth = ++nesting_depth;
-  thisloop->data.loop.start_label = gen_label_rtx ();
-  thisloop->data.loop.end_label = gen_label_rtx ();
-  thisloop->data.loop.continue_label = thisloop->data.loop.start_label;
-  thisloop->exit_label = exit_flag ? thisloop->data.loop.end_label : 0;
-  loop_stack = thisloop;
-  nesting_stack = thisloop;
-
-  do_pending_stack_adjust ();
-  emit_queue ();
-  emit_note (NOTE_INSN_LOOP_BEG);
-  emit_label (thisloop->data.loop.start_label);
-
-  return thisloop;
-}
-
-/* Like expand_start_loop but for a loop where the continuation point
-   (for expand_continue_loop) will be specified explicitly.  */
-
-struct nesting *
-expand_start_loop_continue_elsewhere (int exit_flag)
-{
-  struct nesting *thisloop = expand_start_loop (exit_flag);
-  loop_stack->data.loop.continue_label = gen_label_rtx ();
-  return thisloop;
-}
-
-/* Begin a null, aka do { } while (0) "loop".  But since the contents
-   of said loop can still contain a break, we must frob the loop nest.  */
-
-struct nesting *
-expand_start_null_loop (void)
-{
-  struct nesting *thisloop = ALLOC_NESTING ();
-
-  /* Make an entry on loop_stack for the loop we are entering.  */
-
-  thisloop->desc = LOOP_NESTING;
-  thisloop->next = loop_stack;
-  thisloop->all = nesting_stack;
-  thisloop->depth = ++nesting_depth;
-  thisloop->data.loop.start_label = emit_note (NOTE_INSN_DELETED);
-  thisloop->data.loop.end_label = gen_label_rtx ();
-  thisloop->data.loop.continue_label = thisloop->data.loop.end_label;
-  thisloop->exit_label = thisloop->data.loop.end_label;
-  loop_stack = thisloop;
-  nesting_stack = thisloop;
-
-  return thisloop;
-}
-
-/* Specify the continuation point for a loop started with
-   expand_start_loop_continue_elsewhere.
-   Use this at the point in the code to which a continue statement
-   should jump.  */
-
-void
-expand_loop_continue_here (void)
-{
-  do_pending_stack_adjust ();
-  emit_note (NOTE_INSN_LOOP_CONT);
-  emit_label (loop_stack->data.loop.continue_label);
-}
-
-/* Finish a loop.  Generate a jump back to the top and the loop-exit label.
-   Pop the block off of loop_stack.  */
-
-void
-expand_end_loop (void)
-{
-  rtx start_label = loop_stack->data.loop.start_label;
-  rtx etc_note;
-  int eh_regions, debug_blocks;
-  bool empty_test;
-
-  /* Mark the continue-point at the top of the loop if none elsewhere.  */
-  if (start_label == loop_stack->data.loop.continue_label)
-    emit_note_before (NOTE_INSN_LOOP_CONT, start_label);
-
-  do_pending_stack_adjust ();
-
-  /* If the loop starts with a loop exit, roll that to the end where
-     it will optimize together with the jump back.
-
-     If the loop presently looks like this (in pseudo-C):
-
-       LOOP_BEG
-       start_label:
-         if (test) goto end_label;
-       LOOP_END_TOP_COND
-         body;
-         goto start_label;
-       end_label:
-
-     transform it to look like:
-
-       LOOP_BEG
-         goto start_label;
-       top_label:
-         body;
-       start_label:
-         if (test) goto end_label;
-         goto top_label;
-       end_label:
-
-     We rely on the presence of NOTE_INSN_LOOP_END_TOP_COND to mark
-     the end of the entry conditional.  Without this, our lexical scan
-     can't tell the difference between an entry conditional and a
-     body conditional that exits the loop.  Mistaking the two means
-     that we can misplace the NOTE_INSN_LOOP_CONT note, which can
-     screw up loop unrolling.
-
-     Things will be oh so much better when loop optimization is done
-     off of a proper control flow graph...  */
-
-  /* Scan insns from the top of the loop looking for the END_TOP_COND note.  */
-
-  empty_test = true;
-  eh_regions = debug_blocks = 0;
-  for (etc_note = start_label; etc_note ; etc_note = NEXT_INSN (etc_note))
-    if (GET_CODE (etc_note) == NOTE)
-      {
-       if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_LOOP_END_TOP_COND)
-         break;
-
-       /* We must not walk into a nested loop.  */
-       else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_LOOP_BEG)
-         {
-           etc_note = NULL_RTX;
-           break;
-         }
-
-       /* At the same time, scan for EH region notes, as we don't want
-          to scrog region nesting.  This shouldn't happen, but...  */
-       else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_EH_REGION_BEG)
-         eh_regions++;
-       else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_EH_REGION_END)
-         {
-           if (--eh_regions < 0)
-             /* We've come to the end of an EH region, but never saw the
-                beginning of that region.  That means that an EH region
-                begins before the top of the loop, and ends in the middle
-                of it.  The existence of such a situation violates a basic
-                assumption in this code, since that would imply that even
-                when EH_REGIONS is zero, we might move code out of an
-                exception region.  */
-             abort ();
-         }
-
-       /* Likewise for debug scopes.  In this case we'll either (1) move
-          all of the notes if they are properly nested or (2) leave the
-          notes alone and only rotate the loop at high optimization
-          levels when we expect to scrog debug info.  */
-       else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_BLOCK_BEG)
-         debug_blocks++;
-       else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_BLOCK_END)
-         debug_blocks--;
-      }
-    else if (INSN_P (etc_note))
-      empty_test = false;
-
-  if (etc_note
-      && optimize
-      && ! empty_test
-      && eh_regions == 0
-      && (debug_blocks == 0 || optimize >= 2)
-      && NEXT_INSN (etc_note) != NULL_RTX
-      && ! any_condjump_p (get_last_insn ()))
-    {
-      /* We found one.  Move everything from START to ETC to the end
-        of the loop, and add a jump from the top of the loop.  */
-      rtx top_label = gen_label_rtx ();
-      rtx start_move = start_label;
-
-      /* If the start label is preceded by a NOTE_INSN_LOOP_CONT note,
-        then we want to move this note also.  */
-      if (GET_CODE (PREV_INSN (start_move)) == NOTE
-         && NOTE_LINE_NUMBER (PREV_INSN (start_move)) == NOTE_INSN_LOOP_CONT)
-       start_move = PREV_INSN (start_move);
-
-      emit_label_before (top_label, start_move);
-
-      /* Actually move the insns.  If the debug scopes are nested, we
-        can move everything at once.  Otherwise we have to move them
-        one by one and squeeze out the block notes.  */
-      if (debug_blocks == 0)
-       reorder_insns (start_move, etc_note, get_last_insn ());
-      else
-       {
-         rtx insn, next_insn;
-         for (insn = start_move; insn; insn = next_insn)
-           {
-             /* Figure out which insn comes after this one.  We have
-                to do this before we move INSN.  */
-             next_insn = (insn == etc_note ? NULL : NEXT_INSN (insn));
-
-             if (GET_CODE (insn) == NOTE
-                 && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
-                     || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
-               continue;
-
-             reorder_insns (insn, insn, get_last_insn ());
-           }
-       }
-
-      /* Add the jump from the top of the loop.  */
-      emit_jump_insn_before (gen_jump (start_label), top_label);
-      emit_barrier_before (top_label);
-      start_label = top_label;
-    }
-
-  emit_jump (start_label);
-  emit_note (NOTE_INSN_LOOP_END);
-  emit_label (loop_stack->data.loop.end_label);
-
-  POPSTACK (loop_stack);
-
-  clear_last_expr ();
-}
-
-/* Finish a null loop, aka do { } while (0).  */
-
-void
-expand_end_null_loop (void)
-{
-  do_pending_stack_adjust ();
-  emit_label (loop_stack->data.loop.end_label);
-
-  POPSTACK (loop_stack);
-
-  clear_last_expr ();
-}
-
-/* Generate a jump to the current loop's continue-point.
-   This is usually the top of the loop, but may be specified
-   explicitly elsewhere.  If not currently inside a loop,
-   return 0 and do nothing; caller will print an error message.  */
-
-int
-expand_continue_loop (struct nesting *whichloop)
-{
-  /* Emit information for branch prediction.  */
-  rtx note;
-
-  if (flag_guess_branch_prob)
-    {
-      note = emit_note (NOTE_INSN_PREDICTION);
-      NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_CONTINUE, IS_TAKEN);
-    }
-  clear_last_expr ();
-  if (whichloop == 0)
-    whichloop = loop_stack;
-  if (whichloop == 0)
-    return 0;
-  expand_goto_internal (NULL_TREE, whichloop->data.loop.continue_label,
-                       NULL_RTX);
-  return 1;
-}
-
-/* Generate a jump to exit the current loop.  If not currently inside a loop,
-   return 0 and do nothing; caller will print an error message.  */
-
-int
-expand_exit_loop (struct nesting *whichloop)
-{
-  clear_last_expr ();
-  if (whichloop == 0)
-    whichloop = loop_stack;
-  if (whichloop == 0)
-    return 0;
-  expand_goto_internal (NULL_TREE, whichloop->data.loop.end_label, NULL_RTX);
-  return 1;
-}
-
-/* Generate a conditional jump to exit the current loop if COND
-   evaluates to zero.  If not currently inside a loop,
-   return 0 and do nothing; caller will print an error message.  */
-
-int
-expand_exit_loop_if_false (struct nesting *whichloop, tree cond)
-{
-  rtx label;
-  clear_last_expr ();
-
-  if (whichloop == 0)
-    whichloop = loop_stack;
-  if (whichloop == 0)
-    return 0;
-
-  if (integer_nonzerop (cond))
-    return 1;
-  if (integer_zerop (cond))
-    return expand_exit_loop (whichloop);
-
-  /* Check if we definitely won't need a fixup.  */
-  if (whichloop == nesting_stack)
-    {
-      jumpifnot (cond, whichloop->data.loop.end_label);
-      return 1;
-    }
-
-  /* In order to handle fixups, we actually create a conditional jump
-     around an unconditional branch to exit the loop.  If fixups are
-     necessary, they go before the unconditional branch.  */
-
-  label = gen_label_rtx ();
-  jumpif (cond, label);
-  expand_goto_internal (NULL_TREE, whichloop->data.loop.end_label,
-                       NULL_RTX);
-  emit_label (label);
-
-  return 1;
-}
-
-/* Like expand_exit_loop_if_false except also emit a note marking
-   the end of the conditional.  Should only be used immediately
-   after expand_loop_start.  */
-
-int
-expand_exit_loop_top_cond (struct nesting *whichloop, tree cond)
-{
-  if (! expand_exit_loop_if_false (whichloop, cond))
-    return 0;
-
-  emit_note (NOTE_INSN_LOOP_END_TOP_COND);
-  return 1;
-}
-
 /* Return nonzero if we should preserve sub-expressions as separate
    pseudos.  We never do so if we aren't optimizing.  We always do so
-   if -fexpensive-optimizations.
-
-   Otherwise, we only do so if we are in the "early" part of a loop.  I.e.,
-   the loop may still be a small one.  */
+   if -fexpensive-optimizations.  */
 
 int
 preserve_subexpressions_p (void)
 {
-  rtx insn;
-
   if (flag_expensive_optimizations)
     return 1;
 
-  if (optimize == 0 || cfun == 0 || cfun->stmt == 0 || loop_stack == 0)
+  if (optimize == 0 || cfun == 0 || cfun->stmt == 0)
     return 0;
 
-  insn = get_last_insn_anywhere ();
-
-  return (insn
-         && (INSN_UID (insn) - INSN_UID (loop_stack->data.loop.start_label)
-             < n_non_fixed_regs * 3));
-
+  return 1;
 }
 
-/* Generate a jump to exit the current loop, conditional, binding contour
-   or case statement.  Not all such constructs are visible to this function,
-   only those started with EXIT_FLAG nonzero.  Individual languages use
-   the EXIT_FLAG parameter to control which kinds of constructs you can
-   exit this way.
-
-   If not currently inside anything that can be exited,
-   return 0 and do nothing; caller will print an error message.  */
-
-int
-expand_exit_something (void)
-{
-  struct nesting *n;
-  clear_last_expr ();
-  for (n = nesting_stack; n; n = n->all)
-    if (n->exit_label != 0)
-      {
-       expand_goto_internal (NULL_TREE, n->exit_label, NULL_RTX);
-       return 1;
-      }
-
-  return 0;
-}
 \f
 /* Generate RTL to return from the current function, with no value.
    (That is, we do not do anything about returning any value.)  */
@@ -2882,16 +1841,12 @@ expand_exit_something (void)
 void
 expand_null_return (void)
 {
-  rtx last_insn;
-
-  last_insn = get_last_insn ();
-
   /* If this function was declared to return a value, but we
      didn't, clobber the return registers so that they are not
      propagated live to the rest of the function.  */
   clobber_return_register ();
 
-  expand_null_return_1 (last_insn);
+  expand_null_return_1 ();
 }
 
 /* Generate RTL to return directly from the current function.
@@ -2900,18 +1855,16 @@ expand_null_return (void)
 void
 expand_naked_return (void)
 {
-  rtx last_insn, end_label;
-
-  last_insn = get_last_insn ();
-  end_label = naked_return_label;
+  rtx end_label;
 
   clear_pending_stack_adjust ();
   do_pending_stack_adjust ();
-  clear_last_expr ();
 
+  end_label = naked_return_label;
   if (end_label == 0)
     end_label = naked_return_label = gen_label_rtx ();
-  expand_goto_internal (NULL_TREE, end_label, last_insn);
+
+  emit_jump (end_label);
 }
 
 /* Try to guess whether the value of return means error code.  */
@@ -2962,9 +1915,9 @@ shift_return_value (rtx val)
       shift = (GET_MODE_BITSIZE (GET_MODE (target))
               - BITS_PER_UNIT * int_size_in_bytes (type));
       if (shift > 0)
-       val = expand_binop (GET_MODE (target), ashl_optab,
+       val = expand_shift (LSHIFT_EXPR, GET_MODE (target),
                            gen_lowpart (GET_MODE (target), val),
-                           GEN_INT (shift), target, 1, OPTAB_WIDEN);
+                           build_int_2 (shift, 0), target, 1);
     }
   return val;
 }
@@ -2975,7 +1928,6 @@ shift_return_value (rtx val)
 static void
 expand_value_return (rtx val)
 {
-  rtx last_insn;
   rtx return_reg;
   enum br_predictor pred;
 
@@ -2991,7 +1943,6 @@ expand_value_return (rtx val)
 
     }
 
-  last_insn = get_last_insn ();
   return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
 
   /* Copy the value to the return location
@@ -3002,7 +1953,7 @@ expand_value_return (rtx val)
       tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
       if (targetm.calls.promote_function_return (TREE_TYPE (current_function_decl)))
       {
-       int unsignedp = TREE_UNSIGNED (type);
+       int unsignedp = TYPE_UNSIGNED (type);
        enum machine_mode old_mode
          = DECL_MODE (DECL_RESULT (current_function_decl));
        enum machine_mode mode
@@ -3017,24 +1968,23 @@ expand_value_return (rtx val)
        emit_move_insn (return_reg, val);
     }
 
-  expand_null_return_1 (last_insn);
+  expand_null_return_1 ();
 }
 
-/* Output a return with no value.  If LAST_INSN is nonzero,
-   pretend that the return takes place after LAST_INSN.  */
+/* Output a return with no value.  */
 
 static void
-expand_null_return_1 (rtx last_insn)
+expand_null_return_1 (void)
 {
-  rtx end_label = cleanup_label ? cleanup_label : return_label;
+  rtx end_label;
 
   clear_pending_stack_adjust ();
   do_pending_stack_adjust ();
-  clear_last_expr ();
 
+  end_label = return_label;
   if (end_label == 0)
      end_label = return_label = gen_label_rtx ();
-  expand_goto_internal (NULL_TREE, end_label, last_insn);
+  emit_jump (end_label);
 }
 \f
 /* Generate RTL to evaluate the expression RETVAL and return it
@@ -3043,15 +1993,6 @@ expand_null_return_1 (rtx last_insn)
 void
 expand_return (tree retval)
 {
-  /* If there are any cleanups to be performed, then they will
-     be inserted following LAST_INSN.  It is desirable
-     that the last_insn, for such purposes, should be the
-     last insn before computing the return value.  Otherwise, cleanups
-     which call functions can clobber the return value.  */
-  /* ??? rms: I think that is erroneous, because in C++ it would
-     run destructors on variables that might be used in the subsequent
-     computation of the return value.  */
-  rtx last_insn = 0;
   rtx result_rtl;
   rtx val = 0;
   tree retval_rhs;
@@ -3060,7 +2001,6 @@ expand_return (tree retval)
   if (TREE_CODE (TREE_TYPE (TREE_TYPE (current_function_decl))) == VOID_TYPE)
     {
       expand_expr (retval, NULL_RTX, VOIDmode, 0);
-      emit_queue ();
       expand_null_return ();
       return;
     }
@@ -3074,49 +2014,12 @@ expand_return (tree retval)
     }
   else if (TREE_CODE (retval) == RESULT_DECL)
     retval_rhs = retval;
-  else if ((TREE_CODE (retval) == MODIFY_EXPR || TREE_CODE (retval) == INIT_EXPR)
+  else if ((TREE_CODE (retval) == MODIFY_EXPR
+           || TREE_CODE (retval) == INIT_EXPR)
           && TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL)
     retval_rhs = TREE_OPERAND (retval, 1);
-  else if (VOID_TYPE_P (TREE_TYPE (retval)))
-    /* Recognize tail-recursive call to void function.  */
-    retval_rhs = retval;
   else
-    retval_rhs = NULL_TREE;
-
-  last_insn = get_last_insn ();
-
-  /* Distribute return down conditional expr if either of the sides
-     may involve tail recursion (see test below).  This enhances the number
-     of tail recursions we see.  Don't do this always since it can produce
-     sub-optimal code in some cases and we distribute assignments into
-     conditional expressions when it would help.  */
-
-  if (optimize && retval_rhs != 0
-      && frame_offset == 0
-      && TREE_CODE (retval_rhs) == COND_EXPR
-      && (TREE_CODE (TREE_OPERAND (retval_rhs, 1)) == CALL_EXPR
-         || TREE_CODE (TREE_OPERAND (retval_rhs, 2)) == CALL_EXPR))
-    {
-      rtx label = gen_label_rtx ();
-      tree expr;
-
-      do_jump (TREE_OPERAND (retval_rhs, 0), label, NULL_RTX);
-      start_cleanup_deferral ();
-      expr = build (MODIFY_EXPR, TREE_TYPE (TREE_TYPE (current_function_decl)),
-                   DECL_RESULT (current_function_decl),
-                   TREE_OPERAND (retval_rhs, 1));
-      TREE_SIDE_EFFECTS (expr) = 1;
-      expand_return (expr);
-      emit_label (label);
-
-      expr = build (MODIFY_EXPR, TREE_TYPE (TREE_TYPE (current_function_decl)),
-                   DECL_RESULT (current_function_decl),
-                   TREE_OPERAND (retval_rhs, 2));
-      TREE_SIDE_EFFECTS (expr) = 1;
-      expand_return (expr);
-      end_cleanup_deferral ();
-      return;
-    }
+    retval_rhs = retval;
 
   result_rtl = DECL_RTL (DECL_RESULT (current_function_decl));
 
@@ -3125,12 +2028,11 @@ expand_return (tree retval)
      copying a BLKmode value into registers.  We could put this code in a
      more general area (for use by everyone instead of just function
      call/return), but until this feature is generally usable it is kept here
-     (and in expand_call).  The value must go into a pseudo in case there
-     are cleanups that will clobber the real return register.  */
+     (and in expand_call).  */
 
   if (retval_rhs != 0
       && TYPE_MODE (TREE_TYPE (retval_rhs)) == BLKmode
-      && GET_CODE (result_rtl) == REG)
+      && REG_P (result_rtl))
     {
       int i;
       unsigned HOST_WIDE_INT bitpos, xbitpos;
@@ -3199,9 +2101,7 @@ expand_return (tree retval)
          store_bit_field (dst, bitsize, xbitpos % BITS_PER_WORD, word_mode,
                           extract_bit_field (src, bitsize,
                                              bitpos % BITS_PER_WORD, 1,
-                                             NULL_RTX, word_mode, word_mode,
-                                             BITS_PER_WORD),
-                          BITS_PER_WORD);
+                                             NULL_RTX, word_mode, word_mode));
        }
 
       tmpmode = GET_MODE (result_rtl);
@@ -3230,7 +2130,6 @@ expand_return (tree retval)
        result_reg_mode = tmpmode;
       result_reg = gen_reg_rtx (result_reg_mode);
 
-      emit_queue ();
       for (i = 0; i < n_regs; i++)
        emit_move_insn (operand_subword (result_reg, i, 0, result_reg_mode),
                        result_pseudos[i]);
@@ -3242,7 +2141,7 @@ expand_return (tree retval)
     }
   else if (retval_rhs != 0
           && !VOID_TYPE_P (TREE_TYPE (retval_rhs))
-          && (GET_CODE (result_rtl) == REG
+          && (REG_P (result_rtl)
               || (GET_CODE (result_rtl) == PARALLEL)))
     {
       /* Calculate the return value into a temporary (usually a pseudo
@@ -3253,128 +2152,17 @@ expand_return (tree retval)
       val = assign_temp (nt, 0, 0, 1);
       val = expand_expr (retval_rhs, val, GET_MODE (val), 0);
       val = force_not_mem (val);
-      emit_queue ();
-      /* Return the calculated value, doing cleanups first.  */
+      /* Return the calculated value.  */
       expand_value_return (shift_return_value (val));
     }
   else
     {
-      /* No cleanups or no hard reg used;
-        calculate value into hard return reg.  */
+      /* No hard reg used; calculate value into hard return reg.  */
       expand_expr (retval, const0_rtx, VOIDmode, 0);
-      emit_queue ();
       expand_value_return (result_rtl);
     }
 }
 \f
-/* Attempt to optimize a potential tail recursion call into a goto.
-   ARGUMENTS are the arguments to a CALL_EXPR; LAST_INSN indicates
-   where to place the jump to the tail recursion label.
-
-   Return TRUE if the call was optimized into a goto.  */
-
-int
-optimize_tail_recursion (tree arguments, rtx last_insn)
-{
-  /* Finish checking validity, and if valid emit code to set the
-     argument variables for the new call.  */
-  if (tail_recursion_args (arguments, DECL_ARGUMENTS (current_function_decl)))
-    {
-      if (tail_recursion_label == 0)
-       {
-         tail_recursion_label = gen_label_rtx ();
-         emit_label_after (tail_recursion_label,
-                           tail_recursion_reentry);
-       }
-      emit_queue ();
-      expand_goto_internal (NULL_TREE, tail_recursion_label, last_insn);
-      emit_barrier ();
-      return 1;
-    }
-  return 0;
-}
-
-/* Emit code to alter this function's formal parms for a tail-recursive call.
-   ACTUALS is a list of actual parameter expressions (chain of TREE_LISTs).
-   FORMALS is the chain of decls of formals.
-   Return 1 if this can be done;
-   otherwise return 0 and do not emit any code.  */
-
-static int
-tail_recursion_args (tree actuals, tree formals)
-{
-  tree a = actuals, f = formals;
-  int i;
-  rtx *argvec;
-
-  /* Check that number and types of actuals are compatible
-     with the formals.  This is not always true in valid C code.
-     Also check that no formal needs to be addressable
-     and that all formals are scalars.  */
-
-  /* Also count the args.  */
-
-  for (a = actuals, f = formals, i = 0; a && f; a = TREE_CHAIN (a), f = TREE_CHAIN (f), i++)
-    {
-      if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (a)))
-         != TYPE_MAIN_VARIANT (TREE_TYPE (f)))
-       return 0;
-      if (GET_CODE (DECL_RTL (f)) != REG || DECL_MODE (f) == BLKmode)
-       return 0;
-    }
-  if (a != 0 || f != 0)
-    return 0;
-
-  /* Compute all the actuals.  */
-
-  argvec = alloca (i * sizeof (rtx));
-
-  for (a = actuals, i = 0; a; a = TREE_CHAIN (a), i++)
-    argvec[i] = expand_expr (TREE_VALUE (a), NULL_RTX, VOIDmode, 0);
-
-  /* Find which actual values refer to current values of previous formals.
-     Copy each of them now, before any formal is changed.  */
-
-  for (a = actuals, i = 0; a; a = TREE_CHAIN (a), i++)
-    {
-      int copy = 0;
-      int j;
-      for (f = formals, j = 0; j < i; f = TREE_CHAIN (f), j++)
-       if (reg_mentioned_p (DECL_RTL (f), argvec[i]))
-         {
-           copy = 1;
-           break;
-         }
-      if (copy)
-       argvec[i] = copy_to_reg (argvec[i]);
-    }
-
-  /* Store the values of the actuals into the formals.  */
-
-  for (f = formals, a = actuals, i = 0; f;
-       f = TREE_CHAIN (f), a = TREE_CHAIN (a), i++)
-    {
-      if (GET_MODE (DECL_RTL (f)) == GET_MODE (argvec[i]))
-       emit_move_insn (DECL_RTL (f), argvec[i]);
-      else
-       {
-         rtx tmp = argvec[i];
-         int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_VALUE (a)));
-         promote_mode(TREE_TYPE (TREE_VALUE (a)), GET_MODE (tmp),
-                      &unsignedp, 0);
-         if (DECL_MODE (f) != GET_MODE (DECL_RTL (f)))
-           {
-             tmp = gen_reg_rtx (DECL_MODE (f));
-             convert_move (tmp, argvec[i], unsignedp);
-           }
-         convert_move (DECL_RTL (f), tmp, unsignedp);
-       }
-    }
-
-  free_temp_slots ();
-  return 1;
-}
-\f
 /* Generate the RTL code for entering a binding contour.
    The variables are declared one by one, by calls to `expand_decl'.
 
@@ -3409,13 +2197,7 @@ expand_start_bindings_and_block (int flags, tree block)
     abort ();
 
   /* Create a note to mark the beginning of the block.  */
-  if (block_flag)
-    {
-      note = emit_note (NOTE_INSN_BLOCK_BEG);
-      NOTE_BLOCK (note) = block;
-    }
-  else
-    note = emit_note (NOTE_INSN_DELETED);
+  note = emit_note (NOTE_INSN_DELETED);
 
   /* Make an entry on block_stack for the block we are entering.  */
 
@@ -3423,9 +2205,6 @@ expand_start_bindings_and_block (int flags, tree block)
   thisblock->next = block_stack;
   thisblock->all = nesting_stack;
   thisblock->depth = ++nesting_depth;
-  thisblock->data.block.stack_level = 0;
-  thisblock->data.block.cleanups = 0;
-  thisblock->data.block.exception_region = 0;
   thisblock->data.block.block_target_temp_slot_level = target_temp_slot_level;
 
   thisblock->data.block.conditional_code = 0;
@@ -3438,16 +2217,6 @@ expand_start_bindings_and_block (int flags, tree block)
      never the last instruction.  */
   emit_note (NOTE_INSN_DELETED);
 
-  if (block_stack
-      && !(block_stack->data.block.cleanups == NULL_TREE
-          && block_stack->data.block.outer_cleanups == NULL_TREE))
-    thisblock->data.block.outer_cleanups
-      = tree_cons (NULL_TREE, block_stack->data.block.cleanups,
-                  block_stack->data.block.outer_cleanups);
-  else
-    thisblock->data.block.outer_cleanups = 0;
-  thisblock->data.block.label_chain = 0;
-  thisblock->data.block.innermost_stack_block = stack_block_stack;
   thisblock->data.block.first_insn = note;
   thisblock->data.block.block_start_count = ++current_block_start_count;
   thisblock->exit_label = exit_flag ? gen_label_rtx () : 0;
@@ -3520,16 +2289,6 @@ is_body_block (tree stmt)
   return 0;
 }
 
-/* True if we are currently emitting insns in an area of output code
-   that is controlled by a conditional expression.  This is used by
-   the cleanup handling code to generate conditional cleanup actions.  */
-
-int
-conditional_context (void)
-{
-  return block_stack && block_stack->data.block.conditional_code;
-}
-
 /* Return an opaque pointer to the current nesting level, so frontend code
    can check its own sanity.  */
 
@@ -3539,35 +2298,12 @@ current_nesting_level (void)
   return cfun ? block_stack : 0;
 }
 
-/* Emit a handler label for a nonlocal goto handler.
-   Also emit code to store the handler label in SLOT before BEFORE_INSN.  */
-
-static rtx
-expand_nl_handler_label (rtx slot, rtx before_insn)
-{
-  rtx insns;
-  rtx handler_label = gen_label_rtx ();
-
-  /* Don't let cleanup_cfg delete the handler.  */
-  LABEL_PRESERVE_P (handler_label) = 1;
-
-  start_sequence ();
-  emit_move_insn (slot, gen_rtx_LABEL_REF (Pmode, handler_label));
-  insns = get_insns ();
-  end_sequence ();
-  emit_insn_before (insns, before_insn);
-
-  emit_label (handler_label);
-
-  return handler_label;
-}
-
 /* Emit code to restore vital registers at the beginning of a nonlocal goto
    handler.  */
 static void
 expand_nl_goto_receiver (void)
 {
-    /* Clobber the FP when we get here, so we have to make sure it's
+  /* Clobber the 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));
 
@@ -3632,82 +2368,6 @@ expand_nl_goto_receiver (void)
   emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
 }
 
-/* Make handlers for nonlocal gotos taking place in the function calls in
-   block THISBLOCK.  */
-
-static void
-expand_nl_goto_receivers (struct nesting *thisblock)
-{
-  tree link;
-  rtx afterward = gen_label_rtx ();
-  rtx insns, slot;
-  rtx label_list;
-  int any_invalid;
-
-  /* Record the handler address in the stack slot for that purpose,
-     during this block, saving and restoring the outer value.  */
-  if (thisblock->next != 0)
-    for (slot = nonlocal_goto_handler_slots; slot; slot = XEXP (slot, 1))
-      {
-       rtx save_receiver = gen_reg_rtx (Pmode);
-       emit_move_insn (XEXP (slot, 0), save_receiver);
-
-       start_sequence ();
-       emit_move_insn (save_receiver, XEXP (slot, 0));
-       insns = get_insns ();
-       end_sequence ();
-       emit_insn_before (insns, thisblock->data.block.first_insn);
-      }
-
-  /* Jump around the handlers; they run only when specially invoked.  */
-  emit_jump (afterward);
-
-  /* Make a separate handler for each label.  */
-  link = nonlocal_labels;
-  slot = nonlocal_goto_handler_slots;
-  label_list = NULL_RTX;
-  for (; link; link = TREE_CHAIN (link), slot = XEXP (slot, 1))
-    /* Skip any labels we shouldn't be able to jump to from here,
-       we generate one special handler for all of them below which just calls
-       abort.  */
-    if (! DECL_TOO_LATE (TREE_VALUE (link)))
-      {
-       rtx lab;
-       lab = expand_nl_handler_label (XEXP (slot, 0),
-                                      thisblock->data.block.first_insn);
-       label_list = gen_rtx_EXPR_LIST (VOIDmode, lab, label_list);
-
-       expand_nl_goto_receiver ();
-
-       /* Jump to the "real" nonlocal label.  */
-       expand_goto (TREE_VALUE (link));
-      }
-
-  /* A second pass over all nonlocal labels; this time we handle those
-     we should not be able to jump to at this point.  */
-  link = nonlocal_labels;
-  slot = nonlocal_goto_handler_slots;
-  any_invalid = 0;
-  for (; link; link = TREE_CHAIN (link), slot = XEXP (slot, 1))
-    if (DECL_TOO_LATE (TREE_VALUE (link)))
-      {
-       rtx lab;
-       lab = expand_nl_handler_label (XEXP (slot, 0),
-                                      thisblock->data.block.first_insn);
-       label_list = gen_rtx_EXPR_LIST (VOIDmode, lab, label_list);
-       any_invalid = 1;
-      }
-
-  if (any_invalid)
-    {
-      expand_nl_goto_receiver ();
-      expand_builtin_trap ();
-    }
-
-  nonlocal_goto_handler_labels = label_list;
-  emit_label (afterward);
-}
-
 /* Warn about any unused VARS (which may contain nodes other than
    VAR_DECLs, but such nodes are ignored).  The nodes are connected
    via the TREE_CHAIN field.  */
@@ -3741,7 +2401,8 @@ warn_about_unused_variables (tree vars)
    labels (because the front end does that).  */
 
 void
-expand_end_bindings (tree vars, int mark_ends, int dont_jump_in)
+expand_end_bindings (tree vars, int mark_ends ATTRIBUTE_UNUSED,
+                    int dont_jump_in ATTRIBUTE_UNUSED)
 {
   struct nesting *thisblock = block_stack;
 
@@ -3755,133 +2416,20 @@ expand_end_bindings (tree vars, int mark_ends, int dont_jump_in)
       emit_label (thisblock->exit_label);
     }
 
-  /* If necessary, make handlers for nonlocal gotos taking
-     place in the function calls in this block.  */
-  if (function_call_count != 0 && nonlocal_labels
-      /* Make handler for outermost block
-        if there were any nonlocal gotos to this function.  */
-      && (thisblock->next == 0 ? current_function_has_nonlocal_label
-         /* Make handler for inner block if it has something
-            special to do when you jump out of it.  */
-         : (thisblock->data.block.cleanups != 0
-            || thisblock->data.block.stack_level != 0)))
-    expand_nl_goto_receivers (thisblock);
-
-  /* Don't allow jumping into a block that has a stack level.
-     Cleanups are allowed, though.  */
-  if (dont_jump_in > 0
-      || (dont_jump_in == 0 && thisblock->data.block.stack_level != 0))
-    {
-      struct label_chain *chain;
-
-      /* Any labels in this block are no longer valid to go to.
-        Mark them to cause an error message.  */
-      for (chain = thisblock->data.block.label_chain; chain; chain = chain->next)
-       {
-         DECL_TOO_LATE (chain->label) = 1;
-         /* If any goto without a fixup came to this label,
-            that must be an error, because gotos without fixups
-            come from outside all saved stack-levels.  */
-         if (TREE_ADDRESSABLE (chain->label))
-           error ("%Jlabel '%D' used before containing binding contour",
-                  chain->label, chain->label);
-       }
-    }
-
-  /* Restore stack level in effect before the block
-     (only if variable-size objects allocated).  */
-  /* Perform any cleanups associated with the block.  */
-
-  if (thisblock->data.block.stack_level != 0
-      || thisblock->data.block.cleanups != 0)
-    {
-      int reachable;
-      rtx insn;
-
-      /* Don't let cleanups affect ({...}) constructs.  */
-      int old_expr_stmts_for_value = expr_stmts_for_value;
-      rtx old_last_expr_value = last_expr_value;
-      rtx old_last_expr_alt_rtl = last_expr_alt_rtl;
-      tree old_last_expr_type = last_expr_type;
-      expr_stmts_for_value = 0;
-
-      /* Only clean up here if this point can actually be reached.  */
-      insn = get_last_insn ();
-      if (GET_CODE (insn) == NOTE)
-       insn = prev_nonnote_insn (insn);
-      reachable = (! insn || GET_CODE (insn) != BARRIER);
-
-      /* Do the cleanups.  */
-      expand_cleanups (thisblock->data.block.cleanups, 0, reachable);
-      if (reachable)
-       do_pending_stack_adjust ();
-
-      expr_stmts_for_value = old_expr_stmts_for_value;
-      last_expr_value = old_last_expr_value;
-      last_expr_alt_rtl = old_last_expr_alt_rtl;
-      last_expr_type = old_last_expr_type;
-
-      /* Restore the stack level.  */
-
-      if (reachable && thisblock->data.block.stack_level != 0)
-       {
-         emit_stack_restore (thisblock->next ? SAVE_BLOCK : SAVE_FUNCTION,
-                             thisblock->data.block.stack_level, NULL_RTX);
-         if (nonlocal_goto_handler_slots != 0)
-           emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level,
-                            NULL_RTX);
-       }
-
-      /* Any gotos out of this block must also do these things.
-        Also report any gotos with fixups that came to labels in this
-        level.  */
-      fixup_gotos (thisblock,
-                  thisblock->data.block.stack_level,
-                  thisblock->data.block.cleanups,
-                  thisblock->data.block.first_insn,
-                  dont_jump_in);
-    }
-
-  /* Mark the beginning and end of the scope if requested.
-     We do this now, after running cleanups on the variables
-     just going out of scope, so they are in scope for their cleanups.  */
+  /* Mark the beginning and end of the scope if requested.  */
 
-  if (mark_ends)
-    {
-      rtx note = emit_note (NOTE_INSN_BLOCK_END);
-      NOTE_BLOCK (note) = NOTE_BLOCK (thisblock->data.block.first_insn);
-    }
-  else
-    /* Get rid of the beginning-mark if we don't make an end-mark.  */
-    NOTE_LINE_NUMBER (thisblock->data.block.first_insn) = NOTE_INSN_DELETED;
+  /* Get rid of the beginning-mark if we don't make an end-mark.  */
+  NOTE_LINE_NUMBER (thisblock->data.block.first_insn) = NOTE_INSN_DELETED;
 
   /* Restore the temporary level of TARGET_EXPRs.  */
   target_temp_slot_level = thisblock->data.block.block_target_temp_slot_level;
 
   /* Restore block_stack level for containing block.  */
 
-  stack_block_stack = thisblock->data.block.innermost_stack_block;
   POPSTACK (block_stack);
 
   /* Pop the stack slot nesting and free any slots at this level.  */
-  pop_temp_slots ();
-}
-\f
-/* Generate code to save the stack pointer at the start of the current block
-   and set up to restore it on exit.  */
-
-void
-save_stack_pointer (void)
-{
-  struct nesting *thisblock = block_stack;
-
-  if (thisblock->data.block.stack_level == 0)
-    {
-      emit_stack_save (thisblock->next ? SAVE_BLOCK : SAVE_FUNCTION,
-                      &thisblock->data.block.stack_level,
-                      thisblock->data.block.first_insn);
-      stack_block_stack = thisblock;
-    }
+  pop_temp_slots ();
 }
 \f
 /* Generate RTL for the automatic variable declaration DECL.
@@ -3935,34 +2483,32 @@ expand_decl (tree decl)
       set_mem_attributes (x, decl, 1);
       SET_DECL_RTL (decl, x);
     }
-  else if (DECL_MODE (decl) != BLKmode
-          /* If -ffloat-store, don't put explicit float vars
-             into regs.  */
-          && !(flag_float_store
-               && TREE_CODE (type) == REAL_TYPE)
-          && ! TREE_THIS_VOLATILE (decl)
-          && ! DECL_NONLOCAL (decl)
-          && (DECL_REGISTER (decl) || DECL_ARTIFICIAL (decl) || optimize))
+  else if (use_register_for_decl (decl))
     {
       /* Automatic variable that can go in a register.  */
-      int unsignedp = TREE_UNSIGNED (type);
+      int unsignedp = TYPE_UNSIGNED (type);
       enum machine_mode reg_mode
        = promote_mode (type, DECL_MODE (decl), &unsignedp, 0);
 
       SET_DECL_RTL (decl, gen_reg_rtx (reg_mode));
 
+      /* Note if the object is a user variable.  */
       if (!DECL_ARTIFICIAL (decl))
-       mark_user_reg (DECL_RTL (decl));
-
-      if (POINTER_TYPE_P (type))
-       mark_reg_pointer (DECL_RTL (decl),
-                         TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
+       {
+         mark_user_reg (DECL_RTL (decl));
+
+         /* Trust user variables which have a pointer type to really
+            be pointers.  Do not trust compiler generated temporaries
+            as our type system is totally busted as it relates to
+            pointer arithmetic which translates into lots of compiler
+            generated objects with pointer types, but which are not really
+            pointers.  */
+         if (POINTER_TYPE_P (type))
+           mark_reg_pointer (DECL_RTL (decl),
+                             TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
+       }
 
       maybe_set_unchanging (DECL_RTL (decl), decl);
-
-      /* If something wants our address, try to use ADDRESSOF.  */
-      if (TREE_ADDRESSABLE (decl))
-       put_var_into_stack (decl, /*rescan=*/false);
     }
 
   else if (TREE_CODE (DECL_SIZE_UNIT (decl)) == INTEGER_CST
@@ -3981,8 +2527,8 @@ expand_decl (tree decl)
         to the proper address.  */
       if (DECL_RTL_SET_P (decl))
        {
-         if (GET_CODE (DECL_RTL (decl)) != MEM
-             || GET_CODE (XEXP (DECL_RTL (decl), 0)) != REG)
+         if (!MEM_P (DECL_RTL (decl))
+             || !REG_P (XEXP (DECL_RTL (decl), 0)))
            abort ();
          oldaddr = XEXP (DECL_RTL (decl), 0);
        }
@@ -4011,15 +2557,9 @@ expand_decl (tree decl)
       /* Record the stack pointer on entry to block, if have
         not already done so.  */
       do_pending_stack_adjust ();
-      save_stack_pointer ();
-
-      /* In function-at-a-time mode, variable_size doesn't expand this,
-        so do it now.  */
-      if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
-       expand_expr (TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
-                    const0_rtx, VOIDmode, 0);
 
-      /* Compute the variable's size, in bytes.  */
+      /* Compute the variable's size, in bytes.  This will expand any
+        needed SAVE_EXPRs for the first time.  */
       size = expand_expr (DECL_SIZE_UNIT (decl), NULL_RTX, VOIDmode, 0);
       free_temp_slots ();
 
@@ -4046,6 +2586,60 @@ expand_decl (tree decl)
     }
 }
 \f
+/* Emit code to allocate T_SIZE bytes of dynamic stack space for ALLOC.  */
+void
+expand_stack_alloc (tree alloc, tree t_size)
+{
+  rtx address, dest, size;
+  tree var, type;
+
+  if (TREE_CODE (alloc) != ADDR_EXPR)
+    abort ();
+  var = TREE_OPERAND (alloc, 0);
+  if (TREE_CODE (var) != VAR_DECL)
+    abort ();
+
+  type = TREE_TYPE (var);
+
+  /* Compute the variable's size, in bytes.  */
+  size = expand_expr (t_size, NULL_RTX, VOIDmode, 0);
+  free_temp_slots ();
+
+  /* Allocate space on the stack for the variable.  */
+  address = XEXP (DECL_RTL (var), 0);
+  dest = allocate_dynamic_stack_space (size, address, TYPE_ALIGN (type));
+  if (dest != address)
+    emit_move_insn (address, dest);
+
+  /* Indicate the alignment we actually gave this variable.  */
+#ifdef STACK_BOUNDARY
+  DECL_ALIGN (var) = STACK_BOUNDARY;
+#else
+  DECL_ALIGN (var) = BIGGEST_ALIGNMENT;
+#endif
+  DECL_USER_ALIGN (var) = 0;
+}
+
+/* Emit code to save the current value of stack.  */
+rtx
+expand_stack_save (void)
+{
+  rtx ret = NULL_RTX;
+
+  do_pending_stack_adjust ();
+  emit_stack_save (SAVE_BLOCK, &ret, NULL_RTX);
+  return ret;
+}
+
+/* Emit code to restore the current value of stack.  */
+void
+expand_stack_restore (tree var)
+{
+  rtx sa = DECL_RTL (var);
+
+  emit_stack_restore (SAVE_BLOCK, sa, NULL_RTX);
+}
+\f
 /* Emit code to perform the initialization of a declaration DECL.  */
 
 void
@@ -4071,13 +2665,11 @@ expand_decl_init (tree decl)
          || code == POINTER_TYPE || code == REFERENCE_TYPE)
        expand_assignment (decl, convert (TREE_TYPE (decl), integer_zero_node),
                           0);
-      emit_queue ();
     }
   else if (DECL_INITIAL (decl) && TREE_CODE (DECL_INITIAL (decl)) != TREE_LIST)
     {
       emit_line_note (DECL_SOURCE_LOCATION (decl));
       expand_assignment (decl, DECL_INITIAL (decl), 0);
-      emit_queue ();
     }
 
   /* Don't let the initialization count as "using" the variable.  */
@@ -4089,133 +2681,15 @@ expand_decl_init (tree decl)
   pop_temp_slots ();
 }
 
-/* CLEANUP is an expression to be executed at exit from this binding contour;
-   for example, in C++, it might call the destructor for this variable.
-
-   We wrap CLEANUP in an UNSAVE_EXPR node, so that we can expand the
-   CLEANUP multiple times, and have the correct semantics.  This
-   happens in exception handling, for gotos, returns, breaks that
-   leave the current scope.
-
-   If CLEANUP is nonzero and DECL is zero, we record a cleanup
-   that is not associated with any particular variable.  */
-
-int
-expand_decl_cleanup (tree decl, tree cleanup)
-{
-  struct nesting *thisblock;
-
-  /* Error if we are not in any block.  */
-  if (cfun == 0 || block_stack == 0)
-    return 0;
-
-  thisblock = block_stack;
-
-  /* Record the cleanup if there is one.  */
-
-  if (cleanup != 0)
-    {
-      tree t;
-      rtx seq;
-      tree *cleanups = &thisblock->data.block.cleanups;
-      int cond_context = conditional_context ();
-
-      if (cond_context)
-       {
-         rtx flag = gen_reg_rtx (word_mode);
-         rtx set_flag_0;
-         tree cond;
-
-         start_sequence ();
-         emit_move_insn (flag, const0_rtx);
-         set_flag_0 = get_insns ();
-         end_sequence ();
-
-         thisblock->data.block.last_unconditional_cleanup
-           = emit_insn_after (set_flag_0,
-                               thisblock->data.block.last_unconditional_cleanup);
-
-         emit_move_insn (flag, const1_rtx);
-
-         cond = build_decl (VAR_DECL, NULL_TREE,
-                            lang_hooks.types.type_for_mode (word_mode, 1));
-         SET_DECL_RTL (cond, flag);
-
-         /* Conditionalize the cleanup.  */
-         cleanup = build (COND_EXPR, void_type_node,
-                          lang_hooks.truthvalue_conversion (cond),
-                          cleanup, integer_zero_node);
-         cleanup = fold (cleanup);
-
-         cleanups = &thisblock->data.block.cleanups;
-       }
-
-      cleanup = unsave_expr (cleanup);
-
-      t = *cleanups = tree_cons (decl, cleanup, *cleanups);
-
-      if (! cond_context)
-       /* If this block has a cleanup, it belongs in stack_block_stack.  */
-       stack_block_stack = thisblock;
-
-      if (cond_context)
-       {
-         start_sequence ();
-       }
-
-      if (! using_eh_for_cleanups_p)
-       TREE_ADDRESSABLE (t) = 1;
-      else
-       expand_eh_region_start ();
-
-      if (cond_context)
-       {
-         seq = get_insns ();
-         end_sequence ();
-         if (seq)
-           thisblock->data.block.last_unconditional_cleanup
-             = emit_insn_after (seq,
-                                thisblock->data.block.last_unconditional_cleanup);
-       }
-      else
-       {
-         thisblock->data.block.last_unconditional_cleanup
-           = get_last_insn ();
-         /* When we insert instructions after the last unconditional cleanup,
-            we don't adjust last_insn.  That means that a later add_insn will
-            clobber the instructions we've just added.  The easiest way to
-            fix this is to just insert another instruction here, so that the
-            instructions inserted after the last unconditional cleanup are
-            never the last instruction.  */
-         emit_note (NOTE_INSN_DELETED);
-       }
-    }
-  return 1;
-}
-
-/* Like expand_decl_cleanup, but maybe only run the cleanup if an exception
-   is thrown.  */
-
-int
-expand_decl_cleanup_eh (tree decl, tree cleanup, int eh_only)
-{
-  int ret = expand_decl_cleanup (decl, cleanup);
-  if (cleanup && ret)
-    {
-      tree node = block_stack->data.block.cleanups;
-      CLEANUP_EH_ONLY (node) = eh_only;
-    }
-  return ret;
-}
 \f
 /* DECL is an anonymous union.  CLEANUP is a cleanup for DECL.
    DECL_ELTS is the list of elements that belong to DECL's type.
    In each, the TREE_VALUE is a VAR_DECL, and the TREE_PURPOSE a cleanup.  */
 
 void
-expand_anon_union_decl (tree decl, tree cleanup, tree decl_elts)
+expand_anon_union_decl (tree decl, tree cleanup ATTRIBUTE_UNUSED,
+                       tree decl_elts)
 {
-  struct nesting *thisblock = cfun == 0 ? 0 : block_stack;
   rtx x;
   tree t;
 
@@ -4228,14 +2702,12 @@ expand_anon_union_decl (tree decl, tree cleanup, tree decl_elts)
       }
 
   expand_decl (decl);
-  expand_decl_cleanup (decl, cleanup);
   x = DECL_RTL (decl);
 
   /* Go through the elements, assigning RTL to each.  */
   for (t = decl_elts; t; t = TREE_CHAIN (t))
     {
       tree decl_elt = TREE_VALUE (t);
-      tree cleanup_elt = TREE_PURPOSE (t);
       enum machine_mode mode = TYPE_MODE (TREE_TYPE (decl_elt));
 
       /* If any of the elements are addressable, so is the entire
@@ -4256,14 +2728,14 @@ expand_anon_union_decl (tree decl, tree cleanup, tree decl_elts)
 
       /* (SUBREG (MEM ...)) at RTL generation time is invalid, so we
          instead create a new MEM rtx with the proper mode.  */
-      if (GET_CODE (x) == MEM)
+      if (MEM_P (x))
        {
          if (mode == GET_MODE (x))
            SET_DECL_RTL (decl_elt, x);
          else
            SET_DECL_RTL (decl_elt, adjust_address_nv (x, mode, 0));
        }
-      else if (GET_CODE (x) == REG)
+      else if (REG_P (x))
        {
          if (mode == GET_MODE (x))
            SET_DECL_RTL (decl_elt, x);
@@ -4272,128 +2744,9 @@ expand_anon_union_decl (tree decl, tree cleanup, tree decl_elts)
        }
       else
        abort ();
-
-      /* Record the cleanup if there is one.  */
-
-      if (cleanup != 0)
-       thisblock->data.block.cleanups
-         = tree_cons (decl_elt, cleanup_elt,
-                      thisblock->data.block.cleanups);
     }
 }
 \f
-/* Expand a list of cleanups LIST.
-   Elements may be expressions or may be nested lists.
-
-   If IN_FIXUP is nonzero, we are generating this cleanup for a fixup
-   goto and handle protection regions specially in that case.
-
-   If REACHABLE, we emit code, otherwise just inform the exception handling
-   code about this finalization.  */
-
-static void
-expand_cleanups (tree list, int in_fixup, int reachable)
-{
-  tree tail;
-  for (tail = list; tail; tail = TREE_CHAIN (tail))
-    if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
-      expand_cleanups (TREE_VALUE (tail), in_fixup, reachable);
-    else
-      {
-       if (! in_fixup && using_eh_for_cleanups_p)
-         expand_eh_region_end_cleanup (TREE_VALUE (tail));
-
-       if (reachable && !CLEANUP_EH_ONLY (tail))
-         {
-           /* Cleanups may be run multiple times.  For example,
-              when exiting a binding contour, we expand the
-              cleanups associated with that contour.  When a goto
-              within that binding contour has a target outside that
-              contour, it will expand all cleanups from its scope to
-              the target.  Though the cleanups are expanded multiple
-              times, the control paths are non-overlapping so the
-              cleanups will not be executed twice.  */
-
-           /* We may need to protect from outer cleanups.  */
-           if (in_fixup && using_eh_for_cleanups_p)
-             {
-               expand_eh_region_start ();
-
-               expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
-
-               expand_eh_region_end_fixup (TREE_VALUE (tail));
-             }
-           else
-             expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
-
-           free_temp_slots ();
-         }
-      }
-}
-
-/* Mark when the context we are emitting RTL for as a conditional
-   context, so that any cleanup actions we register with
-   expand_decl_init will be properly conditionalized when those
-   cleanup actions are later performed.  Must be called before any
-   expression (tree) is expanded that is within a conditional context.  */
-
-void
-start_cleanup_deferral (void)
-{
-  /* block_stack can be NULL if we are inside the parameter list.  It is
-     OK to do nothing, because cleanups aren't possible here.  */
-  if (block_stack)
-    ++block_stack->data.block.conditional_code;
-}
-
-/* Mark the end of a conditional region of code.  Because cleanup
-   deferrals may be nested, we may still be in a conditional region
-   after we end the currently deferred cleanups, only after we end all
-   deferred cleanups, are we back in unconditional code.  */
-
-void
-end_cleanup_deferral (void)
-{
-  /* block_stack can be NULL if we are inside the parameter list.  It is
-     OK to do nothing, because cleanups aren't possible here.  */
-  if (block_stack)
-    --block_stack->data.block.conditional_code;
-}
-
-tree
-last_cleanup_this_contour (void)
-{
-  if (block_stack == 0)
-    return 0;
-
-  return block_stack->data.block.cleanups;
-}
-
-/* Return 1 if there are any pending cleanups at this point.
-   Check the current contour as well as contours that enclose
-   the current contour.  */
-
-int
-any_pending_cleanups (void)
-{
-  struct nesting *block;
-
-  if (cfun == NULL || cfun->stmt == NULL || block_stack == 0)
-    return 0;
-
-  if (block_stack->data.block.cleanups != NULL)
-    return 1;
-
-  if (block_stack->data.block.outer_cleanups == 0)
-    return 0;
-
-  for (block = block_stack->next; block; block = block->next)
-    if (block->data.block.cleanups != 0)
-      return 1;
-
-  return 0;
-}
-\f
 /* Enter a case (Pascal) or switch (C) statement.
    Push a block onto case_stack and nesting_stack
    to accumulate the case-labels that are seen
@@ -4429,56 +2782,13 @@ expand_start_case (int exit_flag, tree expr, tree type,
   nesting_stack = thiscase;
 
   do_pending_stack_adjust ();
-  emit_queue ();
 
   /* Make sure case_stmt.start points to something that won't
      need any transformation before expand_end_case.  */
-  if (GET_CODE (get_last_insn ()) != NOTE)
+  if (!NOTE_P (get_last_insn ()))
     emit_note (NOTE_INSN_DELETED);
 
   thiscase->data.case_stmt.start = get_last_insn ();
-
-  start_cleanup_deferral ();
-}
-\f
-static void
-check_seenlabel (void)
-{
-  /* If this is the first label, warn if any insns have been emitted.  */
-  if (case_stack->data.case_stmt.line_number_status >= 0)
-    {
-      rtx insn;
-
-      restore_line_number_status
-       (case_stack->data.case_stmt.line_number_status);
-      case_stack->data.case_stmt.line_number_status = -1;
-
-      for (insn = case_stack->data.case_stmt.start;
-          insn;
-          insn = NEXT_INSN (insn))
-       {
-         if (GET_CODE (insn) == CODE_LABEL)
-           break;
-         if (GET_CODE (insn) != NOTE
-             && (GET_CODE (insn) != INSN || GET_CODE (PATTERN (insn)) != USE))
-           {
-             do
-               insn = PREV_INSN (insn);
-             while (insn && (GET_CODE (insn) != NOTE || NOTE_LINE_NUMBER (insn) < 0));
-
-             /* If insn is zero, then there must have been a syntax error.  */
-             if (insn)
-                {
-                  location_t locus;
-                  locus.file = NOTE_SOURCE_FILE (insn);
-                  locus.line = NOTE_LINE_NUMBER (insn);
-                  warning ("%Hunreachable code at beginning of %s", &locus,
-                           case_stack->data.case_stmt.printname);
-                }
-             break;
-           }
-       }
-    }
 }
 
 /* Accumulate one case or default label inside a case or switch statement.
@@ -4491,7 +2801,6 @@ check_seenlabel (void)
    If VALUE is a duplicate or overlaps, return 2 and do nothing
    except store the (first) duplicate node in *DUPLICATE.
    If VALUE is out of range, return 3 and do nothing.
-   If we are jumping into the scope of a cleanup or var-sized array, return 5.
    Return 0 on success.
 
    Extended to handle range statements.  */
@@ -4507,10 +2816,6 @@ pushcase (tree value, tree (*converter) (tree, tree), tree label,
   if (! (case_stack && case_stack->data.case_stmt.start))
     return 1;
 
-  if (stack_block_stack
-      && stack_block_stack->depth > case_stack->depth)
-    return 5;
-
   index_type = TREE_TYPE (case_stack->data.case_stmt.index_expr);
   nominal_type = case_stack->data.case_stmt.nominal_type;
 
@@ -4522,8 +2827,6 @@ pushcase (tree value, tree (*converter) (tree, tree), tree label,
   if (value != 0)
     value = (*converter) (nominal_type, value);
 
-  check_seenlabel ();
-
   /* Fail if this value is out of range for the actual type of the index
      (which may be narrower than NOMINAL_TYPE).  */
   if (value != 0
@@ -4531,7 +2834,7 @@ pushcase (tree value, tree (*converter) (tree, tree), tree label,
          || ! int_fits_type_p (value, index_type)))
     return 3;
 
-  return add_case_node (value, value, label, duplicate);
+  return add_case_node (value, value, label, duplicate, false);
 }
 
 /* Like pushcase but this case applies to all values between VALUE1 and
@@ -4554,10 +2857,6 @@ pushcase_range (tree value1, tree value2, tree (*converter) (tree, tree),
   if (! (case_stack && case_stack->data.case_stmt.start))
     return 1;
 
-  if (stack_block_stack
-      && stack_block_stack->depth > case_stack->depth)
-    return 5;
-
   index_type = TREE_TYPE (case_stack->data.case_stmt.index_expr);
   nominal_type = case_stack->data.case_stmt.nominal_type;
 
@@ -4565,8 +2864,6 @@ pushcase_range (tree value1, tree value2, tree (*converter) (tree, tree),
   if (index_type == error_mark_node)
     return 0;
 
-  check_seenlabel ();
-
   /* Convert VALUEs to type in which the comparisons are nominally done
      and replace any unspecified value with the corresponding bound.  */
   if (value1 == 0)
@@ -4597,7 +2894,7 @@ pushcase_range (tree value1, tree value2, tree (*converter) (tree, tree),
       || ! int_fits_type_p (value2, index_type))
     return 3;
 
-  return add_case_node (value1, value2, label, duplicate);
+  return add_case_node (value1, value2, label, duplicate, false);
 }
 
 /* Do the actual insertion of a case label for pushcase and pushcase_range
@@ -4605,7 +2902,8 @@ pushcase_range (tree value1, tree value2, tree (*converter) (tree, tree),
    slowdown for large switch statements.  */
 
 int
-add_case_node (tree low, tree high, tree label, tree *duplicate)
+add_case_node (tree low, tree high, tree label, tree *duplicate,
+              bool dont_expand_label)
 {
   struct case_node *p, **q, *r;
 
@@ -4624,7 +2922,8 @@ add_case_node (tree low, tree high, tree label, tree *duplicate)
          return 2;
        }
       case_stack->data.case_stmt.default_label = label;
-      expand_label (label);
+      if (!dont_expand_label)
+        expand_label (label);
       return 0;
     }
 
@@ -4663,7 +2962,8 @@ add_case_node (tree low, tree high, tree label, tree *duplicate)
     r->high = high;
 
   r->code_label = label;
-  expand_label (label);
+  if (!dont_expand_label)
+    expand_label (label);
 
   *q = r;
   r->parent = p;
@@ -4840,326 +3140,6 @@ add_case_node (tree low, tree high, tree label, tree *duplicate)
   return 0;
 }
 \f
-/* Returns the number of possible values of TYPE.
-   Returns -1 if the number is unknown, variable, or if the number does not
-   fit in a HOST_WIDE_INT.
-   Sets *SPARSENESS to 2 if TYPE is an ENUMERAL_TYPE whose values
-   do not increase monotonically (there may be duplicates);
-   to 1 if the values increase monotonically, but not always by 1;
-   otherwise sets it to 0.  */
-
-HOST_WIDE_INT
-all_cases_count (tree type, int *sparseness)
-{
-  tree t;
-  HOST_WIDE_INT count, minval, lastval;
-
-  *sparseness = 0;
-
-  switch (TREE_CODE (type))
-    {
-    case BOOLEAN_TYPE:
-      count = 2;
-      break;
-
-    case CHAR_TYPE:
-      count = 1 << BITS_PER_UNIT;
-      break;
-
-    default:
-    case INTEGER_TYPE:
-      if (TYPE_MAX_VALUE (type) != 0
-         && 0 != (t = fold (build (MINUS_EXPR, type, TYPE_MAX_VALUE (type),
-                                   TYPE_MIN_VALUE (type))))
-         && 0 != (t = fold (build (PLUS_EXPR, type, t,
-                                   convert (type, integer_zero_node))))
-         && host_integerp (t, 1))
-       count = tree_low_cst (t, 1);
-      else
-       return -1;
-      break;
-
-    case ENUMERAL_TYPE:
-      /* Don't waste time with enumeral types with huge values.  */
-      if (! host_integerp (TYPE_MIN_VALUE (type), 0)
-         || TYPE_MAX_VALUE (type) == 0
-         || ! host_integerp (TYPE_MAX_VALUE (type), 0))
-       return -1;
-
-      lastval = minval = tree_low_cst (TYPE_MIN_VALUE (type), 0);
-      count = 0;
-
-      for (t = TYPE_VALUES (type); t != NULL_TREE; t = TREE_CHAIN (t))
-       {
-         HOST_WIDE_INT thisval = tree_low_cst (TREE_VALUE (t), 0);
-
-         if (*sparseness == 2 || thisval <= lastval)
-           *sparseness = 2;
-         else if (thisval != minval + count)
-           *sparseness = 1;
-
-         lastval = thisval;
-         count++;
-       }
-    }
-
-  return count;
-}
-
-#define BITARRAY_TEST(ARRAY, INDEX) \
-  ((ARRAY)[(unsigned) (INDEX) / HOST_BITS_PER_CHAR]\
-                         & (1 << ((unsigned) (INDEX) % HOST_BITS_PER_CHAR)))
-#define BITARRAY_SET(ARRAY, INDEX) \
-  ((ARRAY)[(unsigned) (INDEX) / HOST_BITS_PER_CHAR]\
-                         |= 1 << ((unsigned) (INDEX) % HOST_BITS_PER_CHAR))
-
-/* Set the elements of the bitstring CASES_SEEN (which has length COUNT),
-   with the case values we have seen, assuming the case expression
-   has the given TYPE.
-   SPARSENESS is as determined by all_cases_count.
-
-   The time needed is proportional to COUNT, unless
-   SPARSENESS is 2, in which case quadratic time is needed.  */
-
-void
-mark_seen_cases (tree type, unsigned char *cases_seen, HOST_WIDE_INT count,
-                int sparseness)
-{
-  tree next_node_to_try = NULL_TREE;
-  HOST_WIDE_INT next_node_offset = 0;
-
-  struct case_node *n, *root = case_stack->data.case_stmt.case_list;
-  tree val = make_node (INTEGER_CST);
-
-  TREE_TYPE (val) = type;
-  if (! root)
-    /* Do nothing.  */
-    ;
-  else if (sparseness == 2)
-    {
-      tree t;
-      unsigned HOST_WIDE_INT xlo;
-
-      /* This less efficient loop is only needed to handle
-        duplicate case values (multiple enum constants
-        with the same value).  */
-      TREE_TYPE (val) = TREE_TYPE (root->low);
-      for (t = TYPE_VALUES (type), xlo = 0; t != NULL_TREE;
-          t = TREE_CHAIN (t), xlo++)
-       {
-         TREE_INT_CST_LOW (val) = TREE_INT_CST_LOW (TREE_VALUE (t));
-         TREE_INT_CST_HIGH (val) = TREE_INT_CST_HIGH (TREE_VALUE (t));
-         n = root;
-         do
-           {
-             /* Keep going past elements distinctly greater than VAL.  */
-             if (tree_int_cst_lt (val, n->low))
-               n = n->left;
-
-             /* or distinctly less than VAL.  */
-             else if (tree_int_cst_lt (n->high, val))
-               n = n->right;
-
-             else
-               {
-                 /* We have found a matching range.  */
-                 BITARRAY_SET (cases_seen, xlo);
-                 break;
-               }
-           }
-         while (n);
-       }
-    }
-  else
-    {
-      if (root->left)
-       case_stack->data.case_stmt.case_list = root = case_tree2list (root, 0);
-
-      for (n = root; n; n = n->right)
-       {
-         TREE_INT_CST_LOW (val) = TREE_INT_CST_LOW (n->low);
-         TREE_INT_CST_HIGH (val) = TREE_INT_CST_HIGH (n->low);
-         while (! tree_int_cst_lt (n->high, val))
-           {
-             /* Calculate (into xlo) the "offset" of the integer (val).
-                The element with lowest value has offset 0, the next smallest
-                element has offset 1, etc.  */
-
-             unsigned HOST_WIDE_INT xlo;
-             HOST_WIDE_INT xhi;
-             tree t;
-
-             if (sparseness && TYPE_VALUES (type) != NULL_TREE)
-               {
-                 /* The TYPE_VALUES will be in increasing order, so
-                    starting searching where we last ended.  */
-                 t = next_node_to_try;
-                 xlo = next_node_offset;
-                 xhi = 0;
-                 for (;;)
-                   {
-                     if (t == NULL_TREE)
-                       {
-                         t = TYPE_VALUES (type);
-                         xlo = 0;
-                       }
-                     if (tree_int_cst_equal (val, TREE_VALUE (t)))
-                       {
-                         next_node_to_try = TREE_CHAIN (t);
-                         next_node_offset = xlo + 1;
-                         break;
-                       }
-                     xlo++;
-                     t = TREE_CHAIN (t);
-                     if (t == next_node_to_try)
-                       {
-                         xlo = -1;
-                         break;
-                       }
-                   }
-               }
-             else
-               {
-                 t = TYPE_MIN_VALUE (type);
-                 if (t)
-                   neg_double (TREE_INT_CST_LOW (t), TREE_INT_CST_HIGH (t),
-                               &xlo, &xhi);
-                 else
-                   xlo = xhi = 0;
-                 add_double (xlo, xhi,
-                             TREE_INT_CST_LOW (val), TREE_INT_CST_HIGH (val),
-                             &xlo, &xhi);
-               }
-
-             if (xhi == 0 && xlo < (unsigned HOST_WIDE_INT) count)
-               BITARRAY_SET (cases_seen, xlo);
-
-             add_double (TREE_INT_CST_LOW (val), TREE_INT_CST_HIGH (val),
-                         1, 0,
-                         &TREE_INT_CST_LOW (val), &TREE_INT_CST_HIGH (val));
-           }
-       }
-    }
-}
-
-/* Given a switch statement with an expression that is an enumeration
-   type, warn if any of the enumeration type's literals are not
-   covered by the case expressions of the switch.  Also, warn if there
-   are any extra switch cases that are *not* elements of the
-   enumerated type.
-
-   Historical note:
-
-   At one stage this function would: ``If all enumeration literals
-   were covered by the case expressions, turn one of the expressions
-   into the default expression since it should not be possible to fall
-   through such a switch.''
-
-   That code has since been removed as: ``This optimization is
-   disabled because it causes valid programs to fail.  ANSI C does not
-   guarantee that an expression with enum type will have a value that
-   is the same as one of the enumeration literals.''  */
-
-void
-check_for_full_enumeration_handling (tree type)
-{
-  struct case_node *n;
-  tree chain;
-
-  /* True iff the selector type is a numbered set mode.  */
-  int sparseness = 0;
-
-  /* The number of possible selector values.  */
-  HOST_WIDE_INT size;
-
-  /* For each possible selector value. a one iff it has been matched
-     by a case value alternative.  */
-  unsigned char *cases_seen;
-
-  /* The allocated size of cases_seen, in chars.  */
-  HOST_WIDE_INT bytes_needed;
-
-  size = all_cases_count (type, &sparseness);
-  bytes_needed = (size + HOST_BITS_PER_CHAR) / HOST_BITS_PER_CHAR;
-
-  if (size > 0 && size < 600000
-      /* We deliberately use calloc here, not cmalloc, so that we can suppress
-        this optimization if we don't have enough memory rather than
-        aborting, as xmalloc would do.  */
-      && (cases_seen = really_call_calloc (bytes_needed, 1)) != NULL)
-    {
-      HOST_WIDE_INT i;
-      tree v = TYPE_VALUES (type);
-
-      /* The time complexity of this code is normally O(N), where
-        N being the number of members in the enumerated type.
-        However, if type is an ENUMERAL_TYPE whose values do not
-        increase monotonically, O(N*log(N)) time may be needed.  */
-
-      mark_seen_cases (type, cases_seen, size, sparseness);
-
-      for (i = 0; v != NULL_TREE && i < size; i++, v = TREE_CHAIN (v))
-       if (BITARRAY_TEST (cases_seen, i) == 0)
-         warning ("enumeration value `%s' not handled in switch",
-                  IDENTIFIER_POINTER (TREE_PURPOSE (v)));
-
-      free (cases_seen);
-    }
-
-  /* Now we go the other way around; we warn if there are case
-     expressions that don't correspond to enumerators.  This can
-     occur since C and C++ don't enforce type-checking of
-     assignments to enumeration variables.  */
-
-  if (case_stack->data.case_stmt.case_list
-      && case_stack->data.case_stmt.case_list->left)
-    case_stack->data.case_stmt.case_list
-      = case_tree2list (case_stack->data.case_stmt.case_list, 0);
-  for (n = case_stack->data.case_stmt.case_list; n; n = n->right)
-    {
-      for (chain = TYPE_VALUES (type);
-          chain && !tree_int_cst_equal (n->low, TREE_VALUE (chain));
-          chain = TREE_CHAIN (chain))
-       ;
-
-      if (!chain)
-       {
-         if (TYPE_NAME (type) == 0)
-           warning ("case value `%ld' not in enumerated type",
-                    (long) TREE_INT_CST_LOW (n->low));
-         else
-           warning ("case value `%ld' not in enumerated type `%s'",
-                    (long) TREE_INT_CST_LOW (n->low),
-                    IDENTIFIER_POINTER ((TREE_CODE (TYPE_NAME (type))
-                                         == IDENTIFIER_NODE)
-                                        ? TYPE_NAME (type)
-                                        : DECL_NAME (TYPE_NAME (type))));
-       }
-      if (!tree_int_cst_equal (n->low, n->high))
-       {
-         for (chain = TYPE_VALUES (type);
-              chain && !tree_int_cst_equal (n->high, TREE_VALUE (chain));
-              chain = TREE_CHAIN (chain))
-           ;
-
-         if (!chain)
-           {
-             if (TYPE_NAME (type) == 0)
-               warning ("case value `%ld' not in enumerated type",
-                        (long) TREE_INT_CST_LOW (n->high));
-             else
-               warning ("case value `%ld' not in enumerated type `%s'",
-                        (long) TREE_INT_CST_LOW (n->high),
-                        IDENTIFIER_POINTER ((TREE_CODE (TYPE_NAME (type))
-                                             == IDENTIFIER_NODE)
-                                            ? TYPE_NAME (type)
-                                            : DECL_NAME (TYPE_NAME (type))));
-           }
-       }
-    }
-}
-
-\f
 /* Maximum number of case bit tests.  */
 #define MAX_CASE_BIT_TESTS  3
 
@@ -5208,8 +3188,8 @@ bool lshift_cheap_p (void)
    number of case nodes, i.e. the node with the most cases gets
    tested first.  */
 
-static
-int case_bit_test_cmp (const void *p1, const void *p2)
+static int
+case_bit_test_cmp (const void *p1, const void *p2)
 {
   const struct case_bit_test *d1 = p1;
   const struct case_bit_test *d2 = p2;
@@ -5281,8 +3261,6 @@ emit_case_bit_tests (tree index_type, tree index_expr, tree minval,
                            convert (index_type, index_expr),
                            convert (index_type, minval)));
   index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
-  emit_queue ();
-  index = protect_from_queue (index, 0);
   do_pending_stack_adjust ();
 
   mode = TYPE_MODE (index_type);
@@ -5344,37 +3322,15 @@ expand_end_case_type (tree orig_index, tree orig_type)
 
   index_expr = thiscase->data.case_stmt.index_expr;
   index_type = TREE_TYPE (index_expr);
-  unsignedp = TREE_UNSIGNED (index_type);
+  unsignedp = TYPE_UNSIGNED (index_type);
   if (orig_type == NULL)
     orig_type = TREE_TYPE (orig_index);
 
   do_pending_stack_adjust ();
 
-  /* This might get a spurious warning in the presence of a syntax error;
-     it could be fixed by moving the call to check_seenlabel after the
-     check for error_mark_node, and copying the code of check_seenlabel that
-     deals with case_stack->data.case_stmt.line_number_status /
-     restore_line_number_status in front of the call to end_cleanup_deferral;
-     However, this might miss some useful warnings in the presence of
-     non-syntax errors.  */
-  check_seenlabel ();
-
   /* An ERROR_MARK occurs for various reasons including invalid data type.  */
   if (index_type != error_mark_node)
     {
-      /* If the switch expression was an enumerated type, check that
-        exactly all enumeration literals are covered by the cases.
-        The check is made when -Wswitch was specified and there is no
-        default case, or when -Wswitch-enum was specified.  */
-      if (((warn_switch && !thiscase->data.case_stmt.default_label)
-          || warn_switch_enum)
-         && TREE_CODE (orig_type) == ENUMERAL_TYPE
-         && TREE_CODE (index_expr) != INTEGER_CST)
-       check_for_full_enumeration_handling (orig_type);
-
-      if (warn_switch_default && !thiscase->data.case_stmt.default_label)
-       warning ("switch missing default case");
-
       /* If we don't have a default-label, create one here,
         after the body of the switch.  */
       if (thiscase->data.case_stmt.default_label == 0)
@@ -5453,12 +3409,9 @@ expand_end_case_type (tree orig_index, tree orig_type)
       if (count != 0)
        range = fold (build (MINUS_EXPR, index_type, maxval, minval));
 
-      end_cleanup_deferral ();
-
       if (count == 0)
        {
          expand_expr (index_expr, const0_rtx, VOIDmode, 0);
-         emit_queue ();
          emit_jump (default_label);
        }
 
@@ -5527,11 +3480,9 @@ expand_end_case_type (tree orig_index, tree orig_type)
                  }
            }
 
-         emit_queue ();
          do_pending_stack_adjust ();
 
-         index = protect_from_queue (index, 0);
-         if (GET_CODE (index) == MEM)
+         if (MEM_P (index))
            index = copy_to_reg (index);
          if (GET_CODE (index) == CONST_INT
              || TREE_CODE (index_expr) == INTEGER_CST)
@@ -5667,8 +3618,6 @@ expand_end_case_type (tree orig_index, tree orig_type)
       reorder_insns (before_case, end,
                     thiscase->data.case_stmt.start);
     }
-  else
-    end_cleanup_deferral ();
 
   if (thiscase->exit_label && !exit_done)
     emit_label (thiscase->exit_label);
@@ -5801,6 +3750,7 @@ estimate_case_costs (case_node_ptr node)
 static bool
 same_case_target_p (rtx l1, rtx l2)
 {
+#if 0
   rtx i1, i2;
 
   if (l1 == l2)
@@ -5820,6 +3770,11 @@ same_case_target_p (rtx l1, rtx l2)
     {
       l2 = XEXP (SET_SRC (PATTERN (i2)), 0);
     }
+#endif
+  /* When coming from gimple, we usually won't have emitted either
+     the labels or the body of the switch statement.  The job being
+     done here should be done via jump threading at the tree level.
+     Cases that go the same place should have the same label.  */
   return l1 == l2;
 }
 
@@ -5853,9 +3808,11 @@ group_case_nodes (case_node_ptr head)
 
   while (node)
     {
-      rtx lab = label_rtx (node->code_label);
+      rtx lab;
       case_node_ptr np = node;
 
+      lab = label_rtx (node->code_label);
+
       /* Try to group the successors of NODE with NODE.  */
       while (((np = np->right) != 0)
             /* Do they jump to the same place?  */
@@ -6110,7 +4067,7 @@ node_is_bounded (case_node_ptr node, tree index_type)
 static void
 emit_jump_if_reachable (rtx label)
 {
-  if (GET_CODE (get_last_insn ()) != BARRIER)
+  if (!BARRIER_P (get_last_insn ()))
     emit_jump (label);
 }
 \f
@@ -6145,7 +4102,7 @@ emit_case_nodes (rtx index, case_node_ptr node, rtx default_label,
                 tree index_type)
 {
   /* If INDEX has an unsigned type, we must make unsigned branches.  */
-  int unsignedp = TREE_UNSIGNED (index_type);
+  int unsignedp = TYPE_UNSIGNED (index_type);
   enum machine_mode mode = GET_MODE (index);
   enum machine_mode imode = TYPE_MODE (index_type);
 
@@ -6200,6 +4157,42 @@ emit_case_nodes (rtx index, case_node_ptr node, rtx default_label,
              emit_case_nodes (index, node->right, default_label, index_type);
            }
 
+         /* If both children are single-valued cases with no
+            children, finish up all the work.  This way, we can save
+            one ordered comparison.  */
+         else if (tree_int_cst_equal (node->right->low, node->right->high)
+                  && node->right->left == 0
+                  && node->right->right == 0
+                  && tree_int_cst_equal (node->left->low, node->left->high)
+                  && node->left->left == 0
+                  && node->left->right == 0)
+           {
+             /* Neither node is bounded.  First distinguish the two sides;
+                then emit the code for one side at a time.  */
+
+             /* See if the value matches what the right hand side
+                wants.  */
+             do_jump_if_equal (index,
+                               convert_modes (mode, imode,
+                                              expand_expr (node->right->low,
+                                                           NULL_RTX,
+                                                           VOIDmode, 0),
+                                              unsignedp),
+                               label_rtx (node->right->code_label),
+                               unsignedp);
+
+             /* See if the value matches what the left hand side
+                wants.  */
+             do_jump_if_equal (index,
+                               convert_modes (mode, imode,
+                                              expand_expr (node->left->low,
+                                                           NULL_RTX,
+                                                           VOIDmode, 0),
+                                              unsignedp),
+                               label_rtx (node->left->code_label),
+                               unsignedp);
+           }
+
          else
            {
              /* Neither node is bounded.  First distinguish the two sides;