OSDN Git Service

Initial revision
[pf3gnuchains/gcc-fork.git] / gcc / except.c
1 /* Implements exceptiom handling.
2    Copyright (C) 1989, 92-95, 1996 Free Software Foundation, Inc.
3    Contributed by Mike Stump <mrs@cygnus.com>.
4
5 This file is part of GNU CC.
6
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING.  If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22
23 /* This file contains the exception handling code for the compiler.
24
25    Exception handling is a mechanism by which complex flows of control
26    can be designated.  The central concepts are the `exception region',
27    the associated `exception handler' for that region and the concept of
28    throwing an exception, and the context of the throw.
29
30    Restrictions are, the regions must be non-overlapping, they can be
31    nested, and there can be zero or more per function.  For each
32    region, there is one associated handler.  Regions only ever
33    surround possible context points of throws.  Regions with no such
34    context points can be optimized away, as they are trivial, and it
35    is not possible for the associated handler to ever be used during a
36    throw.
37
38    Semantics are, when an exception is thrown, control is transferred
39    to a handler, and the code of the exception handler is executed.
40    As control is transferred, the machine state (stack pointer, all
41    callee saved registers and possibly the frame pointer) is restored.
42
43    The handler that is selected by a throw, is the handler associated
44    with the smallest (most nested) region that contains the context of
45    the throw, if such a region exists.  If no region exists, the
46    search for a handler continues in the function that called the
47    function that contains the current context of the throw, with the
48    context of the throw then becoming that point in the code that
49    contains the call instruction.
50
51
52    One can add to the basic model the concepts of thrown exception
53    type, and thrown exception value.  Semantics are as above, except a
54    further check is done when finding a handler for the thrown
55    exception to see if the given handler can handle the thrown
56    exception based upon the exception object's type and possibly its
57    value.  A common optimization is when two regions are identical,
58    the handlers are combined into just one handler so the first check
59    of the resulting handler is for the inner (nested) region's
60    handler, and the second one is for the outer region's handler.  To
61    separate these two notions of handlers, we can call the subhandlers
62    `catch blocks', and use the name `handler' to refer to the
63    combination of the two.  Currently, this layer of functionality is
64    managed by the various front ends.
65
66
67    To mark the start of a exception handling region,
68    expand_eh_region_start () is called.  To mark the end, and
69    associate a handler for the region expand_eh_region_end () is used.
70    The front end can use this interface, if useful.  The back end
71    creates exception regions with these routines.  Another interface
72    the front end can use, is TARGET_EXPR.  TARGET_EXPR gives an
73    unwind-protect style interface a la emacs.
74
75
76    In this implementation, regions do not span more than one function.
77
78    In order to help with the task of finding the associated handler for
79    a region, an exception table is built which associates handlers
80    with regions.  A 3-tuple, containing a reference to the start, the
81    end and the handler is sufficient for the exception table.
82
83    In order to help with the task of restoring callee saved registers
84    and performing other associated function exit actions, function
85    `unwinders' can be generated within those function for which a
86    generic function unwinder called __unwind_function () cannot work.
87    Whether the generic __unwind_function can work is machine dependent
88    and possibly function dependent.  The macro DOESNT_NEEED_UNWINDER
89    decides if the current function being compiled needs an unwinder or
90    not.
91
92    The default is for unwinders to be used, as the default generic
93    function unwinder only calls abort ().  The compiler-generated per
94    function function unwinders simply modify the context of thrown
95    exception to be that of the call site, and then arrange for control
96    to be transferred to __throw instead of the function's caller on
97    return, and then return.  */
98
99
100 #include "config.h"
101 #include <stdio.h>
102 #include "rtl.h"
103 #include "tree.h"
104 #include "flags.h"
105 #include "except.h"
106 #include "function.h"
107 #include "insn-flags.h"
108 #include "expr.h"
109 #include "insn-codes.h"
110 #include "regs.h"
111 #include "hard-reg-set.h"
112 #include "insn-config.h"
113 #include "recog.h"
114 #include "output.h"
115
116 /* List of labels use for exception handlers.  Created by
117    find_exception_handler_labels for the optimization passes.  */
118
119 rtx exception_handler_labels;
120
121 /* Nonzero means that throw was used.  Used for now, because __throw
122    is emitted statically in each file.  */
123
124 int throw_used;
125
126 /* A stack used for keeping track of the currectly active exception
127    handling region.  As exceptions regions are started, an entry
128    describing the region is pushed onto this stack.  The current
129    region can be found by looking at the top of the stack, and as we
130    end regions, entries are poped.  */
131
132 struct eh_stack ehstack;
133
134 /* A queue used for tracking which exception regions have closed, but
135    whose handlers have not yet been expanded.  As we end regions, we
136    enqueue the entry onto this queue.  Entries are dequeue from the
137    queue during expand_leftover_cleanups and expand_start_all_catch,
138    and the handlers for regions are expanded in groups in an effort to
139    group all the handlers together in the same region of program space
140    to improve page performance.  We should redo things, so that we
141    either take RTL for the handler, or we expand the handler expressed
142    as a tree immediately at region end time.  */
143
144 struct eh_queue ehqueue;
145
146 /* Insns for the catch clauses.  */
147
148 rtx catch_clauses;
149
150 /* A list of actions for handlers for regions that are not yet
151    closed.  */
152
153 tree protect_list;
154
155 /* Stacks to keep track of various labels.  */
156
157 /* Keeps track of the label to resume to, should one want to resume
158    the normal control flow out of a handler.  Also used to rethrow
159    exceptions caught in handlers, as if they were physically emitted
160    inline.  */
161
162 struct label_node *caught_return_label_stack = NULL;
163
164 /* A spare data area for the front end's own use.  */
165
166 struct label_node *false_label_stack = NULL;
167
168 /* The rtx for the saved PC value.  */
169
170 rtx eh_saved_pc_rtx;
171
172 rtx expand_builtin_return_addr  PROTO((enum built_in_function, int, rtx));
173 \f
174 /* Various support routines to manipulate the various data structures
175    used by the exception handling code.  */
176
177 /* Push a label entry onto the given STACK.  */
178
179 void
180 push_label_entry (stack, rlabel, tlabel)
181      struct label_node **stack;
182      rtx rlabel;
183      tree tlabel;
184 {
185   struct label_node *newnode
186     = (struct label_node *) xmalloc (sizeof (struct label_node));
187
188   if (rlabel)
189     newnode->u.rlabel = rlabel;
190   else
191     newnode->u.tlabel = tlabel;
192   newnode->chain = *stack;
193   *stack = newnode;
194 }
195
196 /* Pop a label entry from the given STACK.  */
197
198 rtx
199 pop_label_entry (stack)
200      struct label_node **stack;
201 {
202   rtx label;
203   struct label_node *tempnode;
204
205   if (! *stack)
206     return NULL_RTX;
207
208   tempnode = *stack;
209   label = tempnode->u.rlabel;
210   *stack = (*stack)->chain;
211   free (tempnode);
212
213   return label;
214 }
215
216 /* Return the top element of the given STACK.  */
217
218 tree
219 top_label_entry (stack)
220      struct label_node **stack;
221 {
222   if (! *stack)
223     return NULL_TREE;
224
225   return (*stack)->u.tlabel;
226 }
227
228 /* Copy an entry.  */
229
230 static struct eh_entry *
231 copy_eh_entry (entry)
232      struct eh_entry *entry;
233 {
234   struct eh_entry *newentry;
235
236   newentry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry));
237   bcopy ((char *) entry, (char *) newentry, sizeof (struct eh_entry));
238
239   return newentry;
240 }
241
242 /* Push an entry onto the given STACK.  */
243
244 static rtx
245 push_eh_entry (stack)
246      struct eh_stack *stack;
247 {
248   struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
249   struct eh_entry *entry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry));
250
251   entry->start_label = gen_label_rtx ();
252   entry->end_label = gen_label_rtx ();
253   entry->exception_handler_label = gen_label_rtx ();
254   entry->finalization = NULL_TREE;
255
256   node->entry = entry;
257   node->chain = stack->top;
258   stack->top = node;
259
260   return entry->start_label;
261 }
262
263 /* Pop an entry from the given STACK.  */
264
265 static struct eh_entry *
266 pop_eh_entry (stack)
267      struct eh_stack *stack;
268 {
269   struct eh_node *tempnode;
270   struct eh_entry *tempentry;
271   
272   tempnode = stack->top;
273   tempentry = tempnode->entry;
274   stack->top = stack->top->chain;
275   free (tempnode);
276
277   return tempentry;
278 }
279
280 /* Enqueue an ENTRY onto the given QUEUE.  */
281
282 static void
283 enqueue_eh_entry (queue, entry)
284      struct eh_queue *queue;
285      struct eh_entry *entry;
286 {
287   struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
288
289   node->entry = entry;
290   node->chain = NULL;
291
292   if (queue->head == NULL)
293     {
294       queue->head = node;
295     }
296   else
297     {
298       queue->tail->chain = node;
299     }
300   queue->tail = node;
301 }
302
303 /* Dequeue an entry from the given QUEUE.  */
304
305 static struct eh_entry *
306 dequeue_eh_entry (queue)
307      struct eh_queue *queue;
308 {
309   struct eh_node *tempnode;
310   struct eh_entry *tempentry;
311
312   if (queue->head == NULL)
313     return NULL;
314
315   tempnode = queue->head;
316   queue->head = queue->head->chain;
317
318   tempentry = tempnode->entry;
319   free (tempnode);
320
321   return tempentry;
322 }
323 \f
324 /* Routine to see if exception exception handling is turned on.
325    DO_WARN is non-zero if we want to inform the user that exception
326    handling is turned off.  */
327
328 int
329 doing_eh (do_warn)
330      int do_warn;
331 {
332   if (! flag_exceptions)
333     {
334       static int warned = 0;
335       if (! warned && do_warn)
336         {
337           error ("exception handling disabled, use -fexceptions to enable");
338           warned = 1;
339         }
340       return 0;
341     }
342   return 1;
343 }
344
345 /* Given the return address in ADDR, compute the new pc to throw.
346    This has to work for the current frame of the current function, and
347    the one above it in the case of throw.  */
348
349 rtx
350 eh_outer_context (addr)
351      rtx addr;
352 {
353   /* First mask out any unwanted bits.  */
354 #ifdef MASK_RETURN_ADDR
355   emit_insn (gen_rtx (SET, Pmode,
356                       addr,
357                       gen_rtx (AND, Pmode,
358                                addr, MASK_RETURN_ADDR)));
359 #endif
360
361   /* Then subtract out enough to get into the prior region.  If this
362      is defined, assume we don't need to subtract anything, as it is
363      already within the region.  */
364 #if ! defined (RETURN_ADDR_OFFSET)
365   addr = plus_constant (addr, -1);
366 #endif
367
368   return addr;
369 }
370
371 /* Output a note marking the start of an exception handling region.  */
372
373 void
374 expand_eh_region_start ()
375 {
376   rtx note;
377
378   /* This is the old code.  */
379   if (! doing_eh (0))
380     return;
381
382 #if 0
383   /* Maybe do this to prevent jumping in and so on...  */
384   pushlevel (0);
385 #endif
386
387   note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_BEG);
388   emit_label (push_eh_entry (&ehstack));
389   NOTE_BLOCK_NUMBER (note)
390     = CODE_LABEL_NUMBER (ehstack.top->entry->exception_handler_label);
391 }
392
393 /* Output a note marking the end of an exception handling region.
394    HANDLER is the the handler for the exception region.  */
395
396 void
397 expand_eh_region_end (handler)
398      tree handler;
399 {
400   rtx note;
401
402   struct eh_entry *entry;
403
404   if (! doing_eh (0))
405     return;
406
407   entry = pop_eh_entry (&ehstack);
408
409   note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END);
410   NOTE_BLOCK_NUMBER (note) = CODE_LABEL_NUMBER (entry->exception_handler_label);
411
412   emit_label (entry->end_label);
413
414   /* Put in something that takes up space, as otherwise the end
415      address for the EH region could have the exact same address as
416      the outer region, causing us to miss the fact that resuming
417      exception handling with this PC value would be inside the outer
418      region.  */
419   emit_insn (gen_nop ());
420
421   entry->finalization = handler;
422
423   enqueue_eh_entry (&ehqueue, entry);
424
425
426 #if 0
427   /* Makebe do this to prevent jumping in and so on...  */
428   poplevel (1, 0, 0);
429 #endif
430 }
431
432 /* Emit a call to __throw and note that we threw something.  */
433
434 static void
435 emit_throw ()
436 {
437 #ifdef JUMP_TO_THROW
438   emit_indirect_jump (throw_libfunc);
439 #else
440   emit_library_call (throw_libfunc, 0, VOIDmode, 0);
441 #endif
442   throw_used = 1;
443   emit_barrier ();
444 }
445
446 /* An internal throw with an indirect CONTEXT we want to throw from.  */
447
448 void
449 expand_internal_throw_indirect (context)
450      rtx context;
451 {
452   emit_move_insn (eh_saved_pc_rtx, context);
453   emit_throw ();
454 }
455
456 /* An internal throw with a direct CONTEXT we want to throw from.  The
457    context should be a label.  */
458
459 void
460 expand_internal_throw (context)
461      rtx context;
462 {
463   expand_internal_throw_indirect (gen_rtx (LABEL_REF, Pmode, context));
464 }
465
466 /* Called from expand_exception_blocks and expand_end_catch_block to
467    expand any pending handlers.  */
468
469 void
470 expand_leftover_cleanups ()
471 {
472   struct eh_entry *entry;
473
474   while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
475     {
476       rtx prev;
477
478       emit_label (entry->exception_handler_label);
479
480       expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
481
482       prev = get_last_insn ();
483       if (! (prev && GET_CODE (prev) == BARRIER))
484         {
485           /* The below can be optimized away, and we could just fall into the
486              next EH handler, if we are certain they are nested.  */
487           /* Code to throw out to outer context, if we fall off end of the
488              handler.  */
489           expand_internal_throw (entry->end_label);
490         }
491
492       /* leftover try block, opps.  */
493       if (entry->finalization == integer_zero_node)
494         abort ();
495
496       free (entry);
497     }
498 }
499
500 /* Generate RTL for the start of all the catch blocks.  Used for
501    arranging for the exception handling code to be placed farther out
502    of line than normal.  */
503
504 void
505 expand_start_all_catch ()
506 {
507   struct eh_entry *entry;
508   tree label;
509
510   if (! doing_eh (1))
511     return;
512
513   emit_line_note (input_filename, lineno);
514   label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
515
516   /* The label for the exception handling block we will save.  This is
517      Lresume, in the documention.  */
518   expand_label (label);
519   
520   /* Put in something that takes up space, as otherwise the end
521      address for the EH region could have the exact same address as
522      the outer region, causing us to miss the fact that resuming
523      exception handling with this PC value would be inside the outer
524      region.  */
525   emit_insn (gen_nop ());
526
527   push_label_entry (&caught_return_label_stack, NULL_RTX, label);
528
529   /* Start a new sequence for all the catch blocks.  We will add this
530      to the gloabl sequence catch_clauses, when we have completed all
531      the handlers in this handler-seq.  */
532   start_sequence ();
533
534   while (1)
535     {
536       rtx prev;
537
538       entry = dequeue_eh_entry (&ehqueue);
539       emit_label (entry->exception_handler_label);
540
541       expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
542
543       /* When we get down to the matching entry, stop.  */
544       if (entry->finalization == integer_zero_node)
545         break;
546
547       prev = get_last_insn ();
548       if (! (prev && GET_CODE (prev) == BARRIER))
549         {
550           /* The below can be optimized away, and we could just fall into the
551              next EH handler, if we are certain they are nested.  */
552           /* Code to throw out to outer context, if we fall off end of the
553              handler.  */
554           expand_internal_throw (entry->end_label);
555         }
556
557       free (entry);
558     }
559 }
560
561 /* Generate RTL for the end of all the catch blocks.  */
562
563 void
564 expand_end_all_catch ()
565 {
566   rtx new_catch_clause;
567
568   if (! doing_eh (1))
569     return;
570
571   /* Code to throw out to outer context, if we fall off end of catch
572      handlers.  This is rethrow (Lresume, same id, same obj); in the
573      documentation.  */
574   expand_internal_throw (DECL_RTL (top_label_entry (&caught_return_label_stack)));
575
576   /* Now we have the complete catch sequence.  */
577   new_catch_clause = get_insns ();
578   end_sequence ();
579   
580   /* This level of catch blocks is done, so set up the successful
581      catch jump label for the next layer of catch blocks.  */
582   pop_label_entry (&caught_return_label_stack);
583
584   /* Add the new sequence of catches to the main one for this function.  */
585   push_to_sequence (catch_clauses);
586   emit_insns (new_catch_clause);
587   catch_clauses = get_insns ();
588   end_sequence ();
589   
590   /* Here we fall through into the continuation code.  */
591 }
592
593 /* End all the pending exception regions from protect_list that have
594    been started, but not yet completed.  */
595
596 void
597 end_protect_partials ()
598 {
599   while (protect_list)
600     {
601       expand_eh_region_end (TREE_VALUE (protect_list));
602       protect_list = TREE_CHAIN (protect_list);
603     }
604 }
605 \f
606 /* The exception table that we build that is used for looking up and
607    dispatching exceptions, it's size, and it's maximum size before we
608    have to extend it.  */
609 static int *eh_table;
610 static int eh_table_size;
611 static int eh_table_max_size;
612
613 /* Note the need for an exception table entry for region N.  If we
614    don't need to output an explicit exception table, avoid all the
615    extra work.  Called during final_scan_insn time.  */
616
617 void
618 add_eh_table_entry (n)
619      int n;
620 {
621 #ifndef OMIT_EH_TABLE
622   if (eh_table_size >= eh_table_max_size)
623     {
624       if (eh_table)
625         {
626           eh_table_max_size += eh_table_max_size>>1;
627
628           if (eh_table_max_size < 0)
629             abort ();
630
631           if ((eh_table = (int *) realloc (eh_table, eh_table_max_size))
632               == 0)
633             fatal ("virtual memory exhausted");
634         }
635       else
636         {
637           eh_table_max_size = 252;
638           eh_table = (int *) xmalloc (eh_table_max_size * sizeof (int));
639         }
640     }
641   eh_table[eh_table_size++] = n;
642 #endif
643 }
644
645 /* Conditional to test to see if we need to output an exception table.
646    Note, on some platforms, we don't have to output a table
647    explicitly.  This routine doesn't mean we don't have one.  */
648
649 int
650 exception_table_p ()
651 {
652   if (eh_table)
653     return 1;
654
655   return 0;
656 }
657
658 /* Output an entry N for the exception table to the specified FILE.  */
659
660 static void
661 output_exception_table_entry (file, n)
662      FILE *file;
663      int n;
664 {
665   char buf[256];
666   rtx sym;
667
668   ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
669   sym = gen_rtx (SYMBOL_REF, Pmode, buf);
670   assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
671
672   ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
673   sym = gen_rtx (SYMBOL_REF, Pmode, buf);
674   assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
675
676   ASM_GENERATE_INTERNAL_LABEL (buf, "L", n);
677   sym = gen_rtx (SYMBOL_REF, Pmode, buf);
678   assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
679
680   putc ('\n', file);            /* blank line */
681 }
682
683 /* Output the exception table if we have one and need one.  */
684
685 void
686 output_exception_table ()
687 {
688   int i;
689   extern FILE *asm_out_file;
690
691   if (! doing_eh (0))
692     return;
693
694   exception_section ();
695
696   /* Beginning marker for table.  */
697   assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
698   assemble_label ("__EXCEPTION_TABLE__");
699
700   assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
701   assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
702   assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
703   putc ('\n', asm_out_file);            /* blank line */
704
705   for (i = 0; i < eh_table_size; ++i)
706     output_exception_table_entry (asm_out_file, eh_table[i]);
707
708   free (eh_table);
709
710   /* Ending marker for table.  */
711   assemble_label ("__EXCEPTION_END__");
712   assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
713   assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
714   assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
715   putc ('\n', asm_out_file);            /* blank line */
716 }
717
718 /* Generate code to initialize the exception table at program startup
719    time.  */
720
721 void
722 register_exception_table ()
723 {
724   emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
725                      VOIDmode, 1,
726                      gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
727                      Pmode);
728 }
729 \f
730 /* Emit the RTL for the start of the per function unwinder for the
731    current function.  */
732
733 void
734 start_eh_unwinder ()
735 {
736 #ifdef DOESNT_NEED_UNWINDER
737   if (DOESNT_NEED_UNWINDER)
738     return;
739 #endif
740
741   expand_eh_region_start ();
742 }
743
744 /* Emit the RTL for the end of the per function unwinder for the
745    current function.  */
746
747 void
748 end_eh_unwinder ()
749 {
750   tree expr;
751   rtx return_val_rtx, ret_val, label, end, insns;
752
753   if (! doing_eh (0))
754     return;
755
756 #ifdef DOESNT_NEED_UNWINDER
757   if (DOESNT_NEED_UNWINDER)
758     return;
759 #endif
760
761   expr = make_node (RTL_EXPR);
762   TREE_TYPE (expr) = void_type_node;
763   RTL_EXPR_RTL (expr) = const0_rtx;
764   TREE_SIDE_EFFECTS (expr) = 1;
765   start_sequence_for_rtl_expr (expr);
766
767   ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
768                                         0, hard_frame_pointer_rtx);
769   return_val_rtx = copy_to_reg (ret_val);
770
771   return_val_rtx = eh_outer_context (return_val_rtx);
772
773   emit_move_insn (eh_saved_pc_rtx, return_val_rtx);
774   
775 #ifdef JUMP_TO_THROW
776   emit_move_insn (ret_val, throw_libfunc);
777 #else
778   label = gen_label_rtx ();
779   emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, label));
780 #endif
781
782 #ifdef RETURN_ADDR_OFFSET
783   return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
784   if (return_val_rtx != ret_val)
785     emit_move_insn (ret_val, return_val_rtx);
786 #endif
787   
788   end = gen_label_rtx ();
789   emit_jump (end);  
790
791   RTL_EXPR_SEQUENCE (expr) = get_insns ();
792   end_sequence ();
793   expand_eh_region_end (expr);
794
795   emit_jump (end);
796
797 #ifndef JUMP_TO_THROW
798   emit_label (label);
799   emit_throw ();
800 #endif
801   
802   expand_leftover_cleanups ();
803
804   emit_label (end);
805 }
806
807 /* Emit the RTL for the per function unwinder for the current
808    function, if needed.  Called after all the code that needs unwind
809    protection is output.  */
810
811 void
812 emit_unwinder ()
813 {
814   rtx insns;
815
816   start_sequence ();
817   start_eh_unwinder ();
818   insns = get_insns ();
819   end_sequence ();
820
821   if (insns)
822     emit_insns_after (insns, get_insns ());
823
824   end_eh_unwinder ();
825 }
826
827 /* Scan the current insns and build a list of handler labels.  Called
828    after the last exception handling region is added to the current
829    function (when the rtl is almost all built for the current
830    function) and before the jump optimization pass.  */
831
832 void
833 find_exception_handler_labels ()
834 {
835   rtx insn;
836   int max_labelno = max_label_num ();
837   int min_labelno = get_first_label_num ();
838   rtx *labels;
839
840   exception_handler_labels = NULL_RTX;
841
842   /* If we aren't doing exception handling, there isn't much to check.  */
843   if (! doing_eh (0))
844     return;
845
846   /* First we generate a handy reference to each label.  */
847
848   labels = (rtx *) alloca ((max_labelno - min_labelno) * sizeof (rtx));
849   labels -= min_labelno;
850
851   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
852     {
853       if (GET_CODE (insn) == CODE_LABEL)
854         if (CODE_LABEL_NUMBER (insn) >= min_labelno
855             && CODE_LABEL_NUMBER (insn) < max_labelno)
856           labels[CODE_LABEL_NUMBER (insn)] = insn;
857     }
858
859   /* Then for each start of a region, we add its label to the list.  */
860   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
861     {
862       if (GET_CODE (insn) == NOTE
863           && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
864         {
865           rtx label = NULL_RTX;
866
867           if (NOTE_BLOCK_NUMBER (insn) >= min_labelno
868               && NOTE_BLOCK_NUMBER (insn) < max_labelno)
869             {
870               label = labels[NOTE_BLOCK_NUMBER (insn)];
871
872               if (label)
873                 exception_handler_labels
874                   = gen_rtx (EXPR_LIST, VOIDmode,
875                              label, exception_handler_labels);
876               else
877                 warning ("didn't find handler for EH region %d",
878                          NOTE_BLOCK_NUMBER (insn));
879             }
880           else
881             warning ("mismatched EH region %d", NOTE_BLOCK_NUMBER (insn));
882         }
883     }
884 }
885
886 /* Do some sanity checking on the exception_handler_labels list.  Can
887    be called after find_exception_handler_labels is called to build
888    the list of exception handlers for the current function, and before
889    we finish processing the current function.  */
890
891 void
892 check_exception_handler_labels ()
893 {
894   rtx insn, handler;
895
896   /* If we aren't doing exception handling, there isn't much to check.  */
897   if (! doing_eh (0))
898     return;
899
900   for (handler = exception_handler_labels;
901        handler;
902        handler = XEXP (handler, 1))
903     {
904       for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
905         {
906           if (GET_CODE (insn) == CODE_LABEL)
907             {
908               if (CODE_LABEL_NUMBER (insn)
909                   == CODE_LABEL_NUMBER (XEXP (handler, 0)))
910                 {
911                   if (insn != XEXP (handler, 0))
912                     warning ("mismatched handler %d",
913                              CODE_LABEL_NUMBER (insn));
914                   break;
915                 }
916             }
917         }
918       if (insn == NULL_RTX)
919         warning ("handler not found %d",
920                  CODE_LABEL_NUMBER (XEXP (handler, 0)));
921     }
922
923   /* Now go through, and make sure that for each region we have, that we
924      have the corresponding label.  */
925   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
926     {
927       if (GET_CODE (insn) == NOTE
928           && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG ||
929               NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
930         {
931           for (handler = exception_handler_labels;
932                handler;
933                handler = XEXP (handler, 1))
934             {
935               if (CODE_LABEL_NUMBER (XEXP (handler, 0))
936                   == NOTE_BLOCK_NUMBER (insn))
937                 break;
938             }
939           if (handler == NULL_RTX)
940             warning ("region exists, no handler %d",
941                      NOTE_BLOCK_NUMBER (insn));
942         }
943     }
944 }
945 \f
946 /* This group of functions initializes the exception handling data
947    structures at the start of the compilation, initializes the data
948    structures at the start of a function, saves and restores the
949    exception handling data structures for the start/end of a nested
950    function.  */
951
952 /* Toplevel initialization for EH things.  */ 
953
954 void
955 init_eh ()
956 {
957   eh_saved_pc_rtx = gen_rtx (MEM, ptr_mode,
958                              gen_rtx (SYMBOL_REF, Pmode, "__eh_pc"));
959 }
960
961 /* Initialize various EH things.  */
962
963 void
964 init_eh_for_function ()
965 {
966   ehstack.top = 0;
967   ehqueue.head = ehqueue.tail = 0;
968   catch_clauses = NULL_RTX;
969   false_label_stack = 0;
970   caught_return_label_stack = 0;
971   protect_list = NULL_TREE;
972 }
973
974 /* Save various EH things for the current function into the save area
975    denoted by P.  */
976
977 void
978 save_eh_status (p)
979      struct function *p;
980 {
981   p->ehstack = ehstack;
982   p->ehqueue = ehqueue;
983   p->catch_clauses = catch_clauses;
984   p->false_label_stack = false_label_stack;
985   p->caught_return_label_stack = caught_return_label_stack;
986   p->protect_list = protect_list;
987
988   init_eh ();
989 }
990
991 /* Restore various EH things for the current function from the save
992    area denoted by P.  */
993
994 void
995 restore_eh_status (p)
996      struct function *p;
997 {
998   protect_list = p->protect_list;
999   caught_return_label_stack = p->caught_return_label_stack;
1000   false_label_stack = p->false_label_stack;
1001   catch_clauses = p->catch_clauses;
1002   ehqueue = p->ehqueue;
1003   ehstack = p->ehstack;
1004 }
1005 \f
1006 /* This section is for the exception handling specific optimization
1007    pass.  First are the internal routines, and then the main
1008    optimization pass.  */
1009
1010 /* Determine if the given INSN can throw an exception.  */
1011
1012 static int
1013 can_throw (insn)
1014      rtx insn;
1015 {
1016   /* The only things that can possibly throw are calls.  */
1017   if (GET_CODE (insn) == CALL_INSN)
1018     return 1;
1019
1020 #ifdef ASYNCH_EXCEPTIONS
1021   /* If we wanted asynchronous exceptions, then everything but NOTEs
1022      and CODE_LABELs could throw.  */
1023   if (GET_CODE (insn) != NOTE && GET_CODE (insn) != CODE_LABEL)
1024     return 1;
1025 #endif
1026
1027   return 0;
1028 }
1029
1030 /* Scan a region, looking for a matching end, and decide if the region
1031    can be removed.  INSN is the start of the region, N is the region
1032    number, and DELETE_OUTER is to note if anything in this region can
1033    throw.  */
1034
1035 static rtx
1036 scan_region (insn, n, delete_outer)
1037      rtx insn;
1038      int n;
1039      int *delete_outer;
1040 {
1041   rtx start = insn;
1042
1043   /* Assume we can delete the region.  */
1044   int delete = 1;
1045
1046   insn = NEXT_INSN (insn);
1047
1048   /* Look for the matching end.  */
1049   while (! (GET_CODE (insn) == NOTE
1050             && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
1051     {
1052       /* If anything can throw, we can't remove the region.  */
1053       if (delete && can_throw (insn))
1054         {
1055           delete = 0;
1056         }
1057
1058       /* Watch out for and handle nested regions.  */
1059       if (GET_CODE (insn) == NOTE
1060           && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
1061         {
1062           insn = scan_region (insn, NOTE_BLOCK_NUMBER (insn), &delete);
1063         }
1064
1065       insn = NEXT_INSN (insn);
1066     }
1067
1068   /* The _BEG/_END NOTEs must match and nest.  */
1069   if (NOTE_BLOCK_NUMBER (insn) != n)
1070     abort ();
1071
1072   /* If anything can throw, we can throw.  */
1073   if (! delete)
1074     *delete_outer = 0;
1075   else
1076     {
1077       /* Delete the start and end of the region.  */
1078       delete_insn (start);
1079       delete_insn (insn);
1080
1081       /* Only do this part if we have built the exception handler
1082          labels.  */
1083       if (exception_handler_labels)
1084         {
1085           rtx x, *prev = &exception_handler_labels;
1086
1087           /* Find it in the list of handlers.  */
1088           for (x = exception_handler_labels; x; x = XEXP (x, 1))
1089             {
1090               rtx label = XEXP (x, 0);
1091               if (CODE_LABEL_NUMBER (label) == n)
1092                 {
1093                   /* If we are the last reference to the handler,
1094                      delete it.  */
1095                   if (--LABEL_NUSES (label) == 0)
1096                     delete_insn (label);
1097
1098                   if (optimize)
1099                     {
1100                       /* Remove it from the list of exception handler
1101                          labels, if we are optimizing.  If we are not, then
1102                          leave it in the list, as we are not really going to
1103                          remove the region.  */
1104                       *prev = XEXP (x, 1);
1105                       XEXP (x, 1) = 0;
1106                       XEXP (x, 0) = 0;
1107                     }
1108
1109                   break;
1110                 }
1111               prev = &XEXP (x, 1);
1112             }
1113         }
1114     }
1115   return insn;
1116 }
1117
1118 /* Perform various interesting optimizations for exception handling
1119    code.
1120
1121    We find empty exception regions, and remove them.  The jump
1122    optimization code will remove the handler if nothing else uses it.  */
1123
1124 void
1125 exception_optimize ()
1126 {
1127   rtx insn, regions = NULL_RTX;
1128   int n;
1129
1130   /* First remove empty regions.  */
1131   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1132     {
1133       if (GET_CODE (insn) == NOTE
1134           && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
1135         {
1136           insn = scan_region (insn, NOTE_BLOCK_NUMBER (insn), &n);
1137         }
1138     }
1139 }