function.c (nonlocal_goto_handler_slots): Renamed from nonlocal_goto_handler_slot...
authorBernd Schmidt <crux@pool.informatik.rwth-aachen.de>
Fri, 20 Nov 1998 07:37:42 +0000 (07:37 +0000)
committerJeff Law <law@gcc.gnu.org>
Fri, 20 Nov 1998 07:37:42 +0000 (00:37 -0700)
        * function.c (nonlocal_goto_handler_slots): Renamed from
        nonlocal_goto_handler_slot; now an EXPR_LIST chain.
        (push_function_context_to): Adjust for this change.
        (pop_function_context_from): Likewise.
        (init_function_start): Likewise.
        (expand_function_end): Likewise.
        * function.h (struct function): Likewise.
        * calls.c (expand_call): Likewise.
        * explow.c (allocate_dynamic_stack_space): Likewise.
        * expr.h (nonlocal_goto_handler_slots): Rename its declaration.
        * stmt.c (declare_nonlocal_label): Make a new handler slot for each
        label.
        (expand_goto): When doing a nonlocal goto, find corresponding handler
        slot for it.  Don't put the label address in the static chain register.
        (expand_end_bindings): Break out nonlocal goto handling code into
        three new functions.
        (expand_nl_handler_label, expand_nl_goto_receiver,
        expand_nl_goto_receivers): New static functions, broken out of
        expand_end_bindings and adapted to create one handler per nonlocal
        label.
        * function.c (delete_handlers): Delete insn if it references any of
        the nonlocal goto handler slots.
        * i960.md (nonlocal_goto): Comment out code that modifies
        static_chain_rtx.
        * sparc.md (nonlocal_goto): Likewise.
        (goto_handler_and_restore_v9): Comment out.
        (goto_handler_and_restore_v9_sp64): Comment out.

From-SVN: r23732

gcc/ChangeLog
gcc/calls.c
gcc/config/i960/i960.md
gcc/config/sparc/sparc.md
gcc/explow.c
gcc/expr.h
gcc/function.c
gcc/function.h
gcc/stmt.c

index fff326d..efd0cd9 100644 (file)
@@ -1,4 +1,34 @@
-Thu Nov 19 23:44:38 1998  Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>
+Fri Nov 20 08:34:00 1998  Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>
+
+       * function.c (nonlocal_goto_handler_slots): Renamed from
+       nonlocal_goto_handler_slot; now an EXPR_LIST chain.
+       (push_function_context_to): Adjust for this change.
+       (pop_function_context_from): Likewise.
+       (init_function_start): Likewise.
+       (expand_function_end): Likewise.
+       * function.h (struct function): Likewise.
+       * calls.c (expand_call): Likewise.
+       * explow.c (allocate_dynamic_stack_space): Likewise.
+       * expr.h (nonlocal_goto_handler_slots): Rename its declaration.
+       * stmt.c (declare_nonlocal_label): Make a new handler slot for each
+       label.
+       (expand_goto): When doing a nonlocal goto, find corresponding handler
+       slot for it.  Don't put the label address in the static chain register.
+       (expand_end_bindings): Break out nonlocal goto handling code into
+       three new functions.
+       (expand_nl_handler_label, expand_nl_goto_receiver,
+       expand_nl_goto_receivers): New static functions, broken out of
+       expand_end_bindings and adapted to create one handler per nonlocal
+       label.
+       * function.c (delete_handlers): Delete insn if it references any of
+       the nonlocal goto handler slots.
+       * i960.md (nonlocal_goto): Comment out code that modifies
+       static_chain_rtx.
+       * sparc.md (nonlocal_goto): Likewise.
+       (goto_handler_and_restore_v9): Comment out.
+       (goto_handler_and_restore_v9_sp64): Comment out.
+
+Thu Nov 19 23:44:38 1998  
 
        * expr.c (STACK_BYTES): Delete unused macro.
        * calls.c: Provide default for PREFERRED_STACK_BOUNDARY.
index 6f67b7c..79cae9f 100644 (file)
@@ -2204,7 +2204,7 @@ expand_call (exp, target, ignore)
      Check for the handler slots since we might not have a save area
      for non-local gotos.  */
 
-  if (may_be_alloca && nonlocal_goto_handler_slot != 0)
+  if (may_be_alloca && nonlocal_goto_handler_slots != 0)
     emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX);
 
   pop_temp_slots ();
index c99c6c1..ef88484 100644 (file)
                           plus_constant (fp, 8)),
                  new_pc);
 
+#if 0
   /* Next, we put the value into the static chain register's save
      area on the stack.  After the ret below, this will be loaded into
      r3 (the static chain).  */
   emit_move_insn (gen_rtx (MEM, SImode,
                           plus_constant (fp, 12)),
                  val);
+#endif
 
   /* We now load pfp (the previous frame pointer) with the value that
      we want fp to be.  */
index 69b68fd..59fcd59 100644 (file)
      really needed.  */
   /*emit_insn (gen_rtx_USE (VOIDmode, frame_pointer_rtx));*/
   emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
+
+#if 0
   /* Return, restoring reg window and jumping to goto handler.  */
   if (TARGET_V9 && GET_CODE (chain) == CONST_INT
       && ! (INTVAL (chain) & ~(HOST_WIDE_INT)0xffffffff))
     }
   /* Put in the static chain register the nonlocal label address.  */
   emit_move_insn (static_chain_rtx, chain);
+#endif
+
   emit_insn (gen_rtx_USE (VOIDmode, static_chain_rtx));
   emit_insn (gen_goto_handler_and_restore (labreg));
   emit_barrier ();
   [(set_attr "type" "misc")
    (set_attr "length" "2")])
 
-(define_insn "goto_handler_and_restore_v9"
-  [(unspec_volatile [(match_operand:SI 0 "register_operand" "=r,r")
-                    (match_operand:SI 1 "register_operand" "=r,r")
-                    (match_operand:SI 2 "const_int_operand" "I,n")] 3)]
-  "TARGET_V9 && ! TARGET_ARCH64"
-  "@
-   return\\t%0+0\\n\\tmov\\t%2, %Y1
-   sethi\\t%%hi(%2), %1\\n\\treturn\\t%0+0\\n\\tor\\t%Y1, %%lo(%2), %Y1"
-  [(set_attr "type" "misc")
-   (set_attr "length" "2,3")])
-
-(define_insn "*goto_handler_and_restore_v9_sp64"
-  [(unspec_volatile [(match_operand:DI 0 "register_operand" "=r,r")
-                    (match_operand:DI 1 "register_operand" "=r,r")
-                    (match_operand:SI 2 "const_int_operand" "I,n")] 3)]
-  "TARGET_V9 && TARGET_ARCH64"
-  "@
-   return\\t%0+0\\n\\tmov\\t%2, %Y1
-   sethi\\t%%hi(%2), %1\\n\\treturn\\t%0+0\\n\\tor\\t%Y1, %%lo(%2), %Y1"
-  [(set_attr "type" "misc")
-   (set_attr "length" "2,3")])
+;;(define_insn "goto_handler_and_restore_v9"
+;;  [(unspec_volatile [(match_operand:SI 0 "register_operand" "=r,r")
+;;                  (match_operand:SI 1 "register_operand" "=r,r")
+;;                  (match_operand:SI 2 "const_int_operand" "I,n")] 3)]
+;;  "TARGET_V9 && ! TARGET_ARCH64"
+;;  "@
+;;   return\\t%0+0\\n\\tmov\\t%2, %Y1
+;;   sethi\\t%%hi(%2), %1\\n\\treturn\\t%0+0\\n\\tor\\t%Y1, %%lo(%2), %Y1"
+;;  [(set_attr "type" "misc")
+;;   (set_attr "length" "2,3")])
+;;
+;;(define_insn "*goto_handler_and_restore_v9_sp64"
+;;  [(unspec_volatile [(match_operand:DI 0 "register_operand" "=r,r")
+;;                  (match_operand:DI 1 "register_operand" "=r,r")
+;;                  (match_operand:SI 2 "const_int_operand" "I,n")] 3)]
+;;  "TARGET_V9 && TARGET_ARCH64"
+;;  "@
+;;   return\\t%0+0\\n\\tmov\\t%2, %Y1
+;;   sethi\\t%%hi(%2), %1\\n\\treturn\\t%0+0\\n\\tor\\t%Y1, %%lo(%2), %Y1"
+;;  [(set_attr "type" "misc")
+;;   (set_attr "length" "2,3")])
 
 ;; Pattern for use after a setjmp to store FP and the return register
 ;; into the stack area.
index 0dbf002..e4ef27d 100644 (file)
@@ -1303,7 +1303,7 @@ allocate_dynamic_stack_space (size, target, known_align)
 #endif
 
   /* Record the new stack level for nonlocal gotos.  */
-  if (nonlocal_goto_handler_slot != 0)
+  if (nonlocal_goto_handler_slots != 0)
     emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX);
 
   return target;
index b1665aa..896bded 100644 (file)
@@ -105,10 +105,12 @@ extern int inhibit_defer_pop;
 
 extern int function_call_count;
 
-/* RTX for stack slot that holds the current handler for nonlocal gotos.
+/* List (chain of EXPR_LIST) of stack slots that hold the current handlers
+   for nonlocal gotos.  There is one for every nonlocal label in the function;
+   this list matches the one in nonlocal_labels.
    Zero when function does not have nonlocal labels.  */
 
-extern rtx nonlocal_goto_handler_slot;
+extern rtx nonlocal_goto_handler_slots;
 
 /* RTX for stack slot that holds the stack pointer value to restore
    for a nonlocal goto.
index fa8b14a..d9575cc 100644 (file)
@@ -247,10 +247,12 @@ int function_call_count;
 
 tree nonlocal_labels;
 
-/* RTX for stack slot that holds the current handler for nonlocal gotos.
+/* List (chain of EXPR_LIST) of stack slots that hold the current handlers
+   for nonlocal gotos.  There is one for every nonlocal label in the function;
+   this list matches the one in nonlocal_labels.
    Zero when function does not have nonlocal labels.  */
 
-rtx nonlocal_goto_handler_slot;
+rtx nonlocal_goto_handler_slots;
 
 /* RTX for stack slot that holds the stack pointer value to restore
    for a nonlocal goto.
@@ -532,7 +534,7 @@ push_function_context_to (context)
   p->parm_reg_stack_loc = parm_reg_stack_loc;
   p->outgoing_args_size = current_function_outgoing_args_size;
   p->return_rtx = current_function_return_rtx;
-  p->nonlocal_goto_handler_slot = nonlocal_goto_handler_slot;
+  p->nonlocal_goto_handler_slots = nonlocal_goto_handler_slots;
   p->nonlocal_goto_stack_level = nonlocal_goto_stack_level;
   p->nonlocal_labels = nonlocal_labels;
   p->cleanup_label = cleanup_label;
@@ -616,7 +618,7 @@ pop_function_context_from (context)
   parm_reg_stack_loc = p->parm_reg_stack_loc;
   current_function_outgoing_args_size = p->outgoing_args_size;
   current_function_return_rtx = p->return_rtx;
-  nonlocal_goto_handler_slot = p->nonlocal_goto_handler_slot;
+  nonlocal_goto_handler_slots = p->nonlocal_goto_handler_slots;
   nonlocal_goto_stack_level = p->nonlocal_goto_stack_level;
   nonlocal_labels = p->nonlocal_labels;
   cleanup_label = p->cleanup_label;
@@ -3664,13 +3666,22 @@ delete_handlers ()
                TREE_CHAIN (last_t) = TREE_CHAIN (t);
            }
        }
-      if (GET_CODE (insn) == INSN
-         && ((nonlocal_goto_handler_slot != 0
-              && reg_mentioned_p (nonlocal_goto_handler_slot, PATTERN (insn)))
+      if (GET_CODE (insn) == INSN)
+       {
+         int can_delete = 0;
+         rtx t;
+         for (t = nonlocal_goto_handler_slots; t != 0; t = XEXP (t, 1))
+           if (reg_mentioned_p (t, PATTERN (insn)))
+             {
+               can_delete = 1;
+               break;
+             }
+         if (can_delete
              || (nonlocal_goto_stack_level != 0
                  && reg_mentioned_p (nonlocal_goto_stack_level,
-                                     PATTERN (insn)))))
-       delete_insn (insn);
+                                     PATTERN (insn))))
+           delete_insn (insn);
+       }
     }
 }
 
@@ -5452,7 +5463,7 @@ init_function_start (subr, filename, line)
   stack_slot_list = 0;
 
   /* There is no stack slot for handling nonlocal gotos.  */
-  nonlocal_goto_handler_slot = 0;
+  nonlocal_goto_handler_slots = 0;
   nonlocal_goto_stack_level = 0;
 
   /* No labels have been declared for nonlocal use.  */
@@ -5972,7 +5983,8 @@ expand_function_end (filename, line, end_bindings)
     }
 
   /* Delete handlers for nonlocal gotos if nothing uses them.  */
-  if (nonlocal_goto_handler_slot != 0 && !current_function_has_nonlocal_label)
+  if (nonlocal_goto_handler_slots != 0
+      && ! current_function_has_nonlocal_label)
     delete_handlers ();
 
   /* End any sequences that failed to be closed due to syntax errors.  */
index d5e6cd0..e78b2e1 100644 (file)
@@ -81,7 +81,7 @@ struct function
   int has_nonlocal_goto;
   int contains_functions;
   int is_thunk;
-  rtx nonlocal_goto_handler_slot;
+  rtx nonlocal_goto_handler_slots;
   rtx nonlocal_goto_stack_level;
   tree nonlocal_labels;
   int args_size;
index 33702db..affd4b5 100644 (file)
@@ -428,6 +428,9 @@ static int using_eh_for_cleanups_p = 0;
 static int n_occurrences               PROTO((int, char *));
 static void expand_goto_internal       PROTO((tree, rtx, rtx));
 static int expand_fixup                        PROTO((tree, rtx, rtx));
+static void expand_nl_handler_label    PROTO((rtx, rtx));
+static void expand_nl_goto_receiver    PROTO((void));
+static void expand_nl_goto_receivers   PROTO((struct nesting *));
 static void fixup_gotos                        PROTO((struct nesting *, rtx, tree,
                                               rtx, int));
 static void expand_null_return_1       PROTO((rtx, int));
@@ -632,16 +635,18 @@ void
 declare_nonlocal_label (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_slot == 0)
+  if (nonlocal_goto_handler_slots == 0)
     {
-      nonlocal_goto_handler_slot
-       = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 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);
 }
 
 /* Generate RTL code for a `goto' statement with target label LABEL.
@@ -660,7 +665,15 @@ expand_goto (label)
     {
       struct function *p = find_function_data (context);
       rtx label_ref = gen_rtx_LABEL_REF (Pmode, label_rtx (label));
-      rtx temp;
+      rtx temp, handler_slot;
+      tree link;
+
+      /* Find the corresponding handler slot for this label.  */
+      handler_slot = p->nonlocal_goto_handler_slots;
+      for (link = p->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;
@@ -673,7 +686,7 @@ expand_goto (label)
 #if HAVE_nonlocal_goto
       if (HAVE_nonlocal_goto)
        emit_insn (gen_nonlocal_goto (lookup_static_chain (label),
-                                     copy_rtx (p->nonlocal_goto_handler_slot),
+                                     copy_rtx (handler_slot),
                                      copy_rtx (p->nonlocal_goto_stack_level),
                                      label_ref));
       else
@@ -695,7 +708,7 @@ expand_goto (label)
 
          /* Get addr of containing function's current nonlocal goto handler,
             which will do any cleanups and then jump to the label.  */
-         addr = copy_rtx (p->nonlocal_goto_handler_slot);
+         addr = copy_rtx (handler_slot);
          temp = copy_to_reg (replace_rtx (addr, virtual_stack_vars_rtx,
                                           hard_frame_pointer_rtx));
          
@@ -708,13 +721,10 @@ expand_goto (label)
 
          emit_stack_restore (SAVE_NONLOCAL, addr, NULL_RTX);
 
-         /* Put in the static chain register the nonlocal label address.  */
-         emit_move_insn (static_chain_rtx, label_ref);
          /* 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_insn (gen_rtx_USE (VOIDmode, static_chain_rtx));
          emit_indirect_jump (temp);
        }
      }
@@ -2992,6 +3002,161 @@ remember_end_note (block)
   last_block_end_note = NULL_RTX;
 }
 
+/* Emit a handler label for a nonlocal goto handler.
+   Also emit code to store the handler label in SLOT before BEFORE_INSN.  */
+
+static void
+expand_nl_handler_label (slot, before_insn)
+     rtx slot, before_insn;
+{
+  rtx insns;
+  rtx handler_label = gen_label_rtx ();
+
+  /* Don't let jump_optimize 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_insns_before (insns, before_insn);
+
+  emit_label (handler_label);
+}
+
+/* Emit code to restore vital registers at the beginning of a nonlocal goto
+   handler.  */
+static void
+expand_nl_goto_receiver ()
+{
+#ifdef HAVE_nonlocal_goto
+  if (! HAVE_nonlocal_goto)
+#endif
+    /* First adjust our frame pointer to its actual value.  It was
+       previously set to the start of the virtual area corresponding to
+       the stacked variables when we branched here and now needs to be
+       adjusted to the actual hardware fp value.
+
+       Assignments are to virtual registers are converted by
+       instantiate_virtual_regs into the corresponding assignment
+       to the underlying register (fp in this case) that makes
+       the original assignment true.
+       So the following insn will actually be
+       decrementing fp by STARTING_FRAME_OFFSET.  */
+    emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
+
+#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+  if (fixed_regs[ARG_POINTER_REGNUM])
+    {
+#ifdef ELIMINABLE_REGS
+      /* If the argument pointer can be eliminated in favor of the
+        frame pointer, we don't need to restore it.  We assume here
+        that if such an elimination is present, it can always be used.
+        This is the case on all known machines; if we don't make this
+        assumption, we do unnecessary saving on many machines.  */
+      static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
+      size_t i;
+
+      for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
+       if (elim_regs[i].from == ARG_POINTER_REGNUM
+           && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
+         break;
+
+      if (i == sizeof elim_regs / sizeof elim_regs [0])
+#endif
+       {
+         /* Now restore our arg pointer from the address at which it
+            was saved in our stack frame.
+            If there hasn't be space allocated for it yet, make
+            some now.  */
+         if (arg_pointer_save_area == 0)
+           arg_pointer_save_area
+             = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
+         emit_move_insn (virtual_incoming_args_rtx,
+                         /* We need a pseudo here, or else
+                            instantiate_virtual_regs_1 complains.  */
+                         copy_to_reg (arg_pointer_save_area));
+       }
+    }
+#endif
+
+#ifdef HAVE_nonlocal_goto_receiver
+  if (HAVE_nonlocal_goto_receiver)
+    emit_insn (gen_nonlocal_goto_receiver ());
+#endif
+}
+
+/* Make handlers for nonlocal gotos taking place in the function calls in
+   block THISBLOCK.  */
+
+static void
+expand_nl_goto_receivers (thisblock)
+     struct nesting *thisblock;
+{
+  tree link;
+  rtx afterward = gen_label_rtx ();
+  rtx insns, slot;
+  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_insns_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;
+  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)))
+      {
+       expand_nl_handler_label (XEXP (slot, 0),
+                                thisblock->data.block.first_insn);
+       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)))
+      {
+       expand_nl_handler_label (XEXP (slot, 0),
+                                thisblock->data.block.first_insn);
+       any_invalid = 1;
+      }
+
+  if (any_invalid)
+    {
+      expand_nl_goto_receiver ();
+      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "abort"), 0,
+                        VOIDmode, 0);
+      emit_barrier ();
+    }
+
+  emit_label (afterward);
+}
+
 /* Generate RTL code to terminate a binding contour.
    VARS is the chain of VAR_DECL nodes
    for the variables bound in this contour.
@@ -3042,7 +3207,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
       emit_label (thisblock->exit_label);
     }
 
-  /* If necessary, make a handler for nonlocal gotos taking
+  /* If necessary, make handlers for nonlocal gotos taking
      place in the function calls in this block.  */
   if (function_call_count != thisblock->data.block.function_call_count
       && nonlocal_labels
@@ -3053,119 +3218,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
             special to do when you jump out of it.  */
          : (thisblock->data.block.cleanups != 0
             || thisblock->data.block.stack_level != 0)))
-    {
-      tree link;
-      rtx afterward = gen_label_rtx ();
-      rtx handler_label = gen_label_rtx ();
-      rtx save_receiver = gen_reg_rtx (Pmode);
-      rtx insns;
-
-      /* Don't let jump_optimize delete the handler.  */
-      LABEL_PRESERVE_P (handler_label) = 1;
-
-      /* Record the handler address in the stack slot for that purpose,
-        during this block, saving and restoring the outer value.  */
-      if (thisblock->next != 0)
-       {
-         emit_move_insn (nonlocal_goto_handler_slot, save_receiver);
-
-         start_sequence ();
-         emit_move_insn (save_receiver, nonlocal_goto_handler_slot);
-         insns = get_insns ();
-         end_sequence ();
-         emit_insns_before (insns, thisblock->data.block.first_insn);
-       }
-
-      start_sequence ();
-      emit_move_insn (nonlocal_goto_handler_slot,
-                     gen_rtx_LABEL_REF (Pmode, handler_label));
-      insns = get_insns ();
-      end_sequence ();
-      emit_insns_before (insns, thisblock->data.block.first_insn);
-
-      /* Jump around the handler; it runs only when specially invoked.  */
-      emit_jump (afterward);
-      emit_label (handler_label);
-
-#ifdef HAVE_nonlocal_goto
-      if (! HAVE_nonlocal_goto)
-#endif
-       /* First adjust our frame pointer to its actual value.  It was
-          previously set to the start of the virtual area corresponding to
-          the stacked variables when we branched here and now needs to be
-          adjusted to the actual hardware fp value.
-
-          Assignments are to virtual registers are converted by
-          instantiate_virtual_regs into the corresponding assignment
-          to the underlying register (fp in this case) that makes
-          the original assignment true.
-          So the following insn will actually be
-          decrementing fp by STARTING_FRAME_OFFSET.  */
-       emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
-
-#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
-      if (fixed_regs[ARG_POINTER_REGNUM])
-       {
-#ifdef ELIMINABLE_REGS
-         /* If the argument pointer can be eliminated in favor of the
-            frame pointer, we don't need to restore it.  We assume here
-            that if such an elimination is present, it can always be used.
-            This is the case on all known machines; if we don't make this
-            assumption, we do unnecessary saving on many machines.  */
-         static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
-         size_t i;
-
-         for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
-           if (elim_regs[i].from == ARG_POINTER_REGNUM
-               && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
-             break;
-
-         if (i == sizeof elim_regs / sizeof elim_regs [0])
-#endif
-           {
-             /* Now restore our arg pointer from the address at which it
-                was saved in our stack frame.
-                If there hasn't be space allocated for it yet, make
-                some now.  */
-             if (arg_pointer_save_area == 0)
-               arg_pointer_save_area
-                 = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
-             emit_move_insn (virtual_incoming_args_rtx,
-                             /* We need a pseudo here, or else
-                                instantiate_virtual_regs_1 complains.  */
-                             copy_to_reg (arg_pointer_save_area));
-           }
-       }
-#endif
-
-#ifdef HAVE_nonlocal_goto_receiver
-      if (HAVE_nonlocal_goto_receiver)
-       emit_insn (gen_nonlocal_goto_receiver ());
-#endif
-
-      /* The handler expects the desired label address in the static chain
-        register.  It tests the address and does an appropriate jump
-        to whatever label is desired.  */
-      for (link = nonlocal_labels; link; link = TREE_CHAIN (link))
-       /* Skip any labels we shouldn't be able to jump to from here.  */
-       if (! DECL_TOO_LATE (TREE_VALUE (link)))
-         {
-           rtx not_this = gen_label_rtx ();
-           rtx this = gen_label_rtx ();
-           do_jump_if_equal (static_chain_rtx,
-                             gen_rtx_LABEL_REF (Pmode, DECL_RTL (TREE_VALUE (link))),
-                             this, 0);
-           emit_jump (not_this);
-           emit_label (this);
-           expand_goto (TREE_VALUE (link));
-           emit_label (not_this);
-         }
-      /* If label is not recognized, abort.  */
-      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "abort"), 0,
-                        VOIDmode, 0);
-      emit_barrier ();
-      emit_label (afterward);
-    }
+    expand_nl_goto_receivers (thisblock);
 
   /* Don't allow jumping into a block that has a stack level.
      Cleanups are allowed, though.  */
@@ -3219,7 +3272,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
        {
          emit_stack_restore (thisblock->next ? SAVE_BLOCK : SAVE_FUNCTION,
                              thisblock->data.block.stack_level, NULL_RTX);
-         if (nonlocal_goto_handler_slot != 0)
+         if (nonlocal_goto_handler_slots != 0)
            emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level,
                             NULL_RTX);
        }
@@ -3266,8 +3319,6 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
   /* Pop the stack slot nesting and free any slots at this level.  */
   pop_temp_slots ();
 }
-
-
 \f
 /* Generate RTL for the automatic variable declaration DECL.
    (Other kinds of declarations are simply ignored if seen here.)  */