OSDN Git Service

* print-tree.c (print_node): Print base for OFFSET_TYPEs.
[pf3gnuchains/gcc-fork.git] / gcc / except.c
1 /* Implements exception handling.
2    Copyright (C) 1989, 1992-1999 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 /* An exception is an event that can be signaled from within a
24    function. This event can then be "caught" or "trapped" by the
25    callers of this function. This potentially allows program flow to
26    be transferred to any arbitrary code associated with a function call
27    several levels up the stack.
28
29    The intended use for this mechanism is for signaling "exceptional
30    events" in an out-of-band fashion, hence its name. The C++ language
31    (and many other OO-styled or functional languages) practically
32    requires such a mechanism, as otherwise it becomes very difficult
33    or even impossible to signal failure conditions in complex
34    situations.  The traditional C++ example is when an error occurs in
35    the process of constructing an object; without such a mechanism, it
36    is impossible to signal that the error occurs without adding global
37    state variables and error checks around every object construction.
38
39    The act of causing this event to occur is referred to as "throwing
40    an exception". (Alternate terms include "raising an exception" or
41    "signaling an exception".) The term "throw" is used because control
42    is returned to the callers of the function that is signaling the
43    exception, and thus there is the concept of "throwing" the
44    exception up the call stack.
45
46    There are two major codegen options for exception handling.  The
47    flag -fsjlj-exceptions can be used to select the setjmp/longjmp
48    approach, which is the default.  -fno-sjlj-exceptions can be used to
49    get the PC range table approach.  While this is a compile time
50    flag, an entire application must be compiled with the same codegen
51    option.  The first is a PC range table approach, the second is a
52    setjmp/longjmp based scheme.  We will first discuss the PC range
53    table approach, after that, we will discuss the setjmp/longjmp
54    based approach.
55
56    It is appropriate to speak of the "context of a throw". This
57    context refers to the address where the exception is thrown from,
58    and is used to determine which exception region will handle the
59    exception.
60
61    Regions of code within a function can be marked such that if it
62    contains the context of a throw, control will be passed to a
63    designated "exception handler". These areas are known as "exception
64    regions".  Exception regions cannot overlap, but they can be nested
65    to any arbitrary depth. Also, exception regions cannot cross
66    function boundaries.
67
68    Exception handlers can either be specified by the user (which we
69    will call a "user-defined handler") or generated by the compiler
70    (which we will designate as a "cleanup"). Cleanups are used to
71    perform tasks such as destruction of objects allocated on the
72    stack.
73
74    In the current implementation, cleanups are handled by allocating an
75    exception region for the area that the cleanup is designated for,
76    and the handler for the region performs the cleanup and then
77    rethrows the exception to the outer exception region. From the
78    standpoint of the current implementation, there is little
79    distinction made between a cleanup and a user-defined handler, and
80    the phrase "exception handler" can be used to refer to either one
81    equally well. (The section "Future Directions" below discusses how
82    this will change).
83
84    Each object file that is compiled with exception handling contains
85    a static array of exception handlers named __EXCEPTION_TABLE__.
86    Each entry contains the starting and ending addresses of the
87    exception region, and the address of the handler designated for
88    that region.
89
90    If the target does not use the DWARF 2 frame unwind information, at
91    program startup each object file invokes a function named
92    __register_exceptions with the address of its local
93    __EXCEPTION_TABLE__. __register_exceptions is defined in libgcc2.c, and
94    is responsible for recording all of the exception regions into one list
95    (which is kept in a static variable named exception_table_list).
96
97    On targets that support crtstuff.c, the unwind information
98    is stored in a section named .eh_frame and the information for the
99    entire shared object or program is registered with a call to
100    __register_frame_info.  On other targets, the information for each
101    translation unit is registered from the file generated by collect2.
102    __register_frame_info is defined in frame.c, and is responsible for
103    recording all of the unwind regions into one list (which is kept in a
104    static variable named unwind_table_list).
105
106    The function __throw is actually responsible for doing the
107    throw. On machines that have unwind info support, __throw is generated
108    by code in libgcc2.c, otherwise __throw is generated on a
109    per-object-file basis for each source file compiled with
110    -fexceptions by the C++ frontend.  Before __throw is invoked,
111    the current context of the throw needs to be placed in the global
112    variable __eh_pc.
113
114    __throw attempts to find the appropriate exception handler for the 
115    PC value stored in __eh_pc by calling __find_first_exception_table_match
116    (which is defined in libgcc2.c). If __find_first_exception_table_match
117    finds a relevant handler, __throw transfers control directly to it.
118
119    If a handler for the context being thrown from can't be found, __throw
120    walks (see Walking the stack below) the stack up the dynamic call chain to
121    continue searching for an appropriate exception handler based upon the
122    caller of the function it last sought a exception handler for.  It stops
123    then either an exception handler is found, or when the top of the
124    call chain is reached.
125
126    If no handler is found, an external library function named
127    __terminate is called.  If a handler is found, then we restart
128    our search for a handler at the end of the call chain, and repeat
129    the search process, but instead of just walking up the call chain,
130    we unwind the call chain as we walk up it.
131
132    Internal implementation details:
133
134    To associate a user-defined handler with a block of statements, the
135    function expand_start_try_stmts is used to mark the start of the
136    block of statements with which the handler is to be associated
137    (which is known as a "try block"). All statements that appear
138    afterwards will be associated with the try block.
139
140    A call to expand_start_all_catch marks the end of the try block,
141    and also marks the start of the "catch block" (the user-defined
142    handler) associated with the try block.
143
144    This user-defined handler will be invoked for *every* exception
145    thrown with the context of the try block. It is up to the handler
146    to decide whether or not it wishes to handle any given exception,
147    as there is currently no mechanism in this implementation for doing
148    this. (There are plans for conditionally processing an exception
149    based on its "type", which will provide a language-independent
150    mechanism).
151
152    If the handler chooses not to process the exception (perhaps by
153    looking at an "exception type" or some other additional data
154    supplied with the exception), it can fall through to the end of the
155    handler. expand_end_all_catch and expand_leftover_cleanups
156    add additional code to the end of each handler to take care of
157    rethrowing to the outer exception handler.
158
159    The handler also has the option to continue with "normal flow of
160    code", or in other words to resume executing at the statement
161    immediately after the end of the exception region. The variable
162    caught_return_label_stack contains a stack of labels, and jumping
163    to the topmost entry's label via expand_goto will resume normal
164    flow to the statement immediately after the end of the exception
165    region. If the handler falls through to the end, the exception will
166    be rethrown to the outer exception region.
167
168    The instructions for the catch block are kept as a separate
169    sequence, and will be emitted at the end of the function along with
170    the handlers specified via expand_eh_region_end. The end of the
171    catch block is marked with expand_end_all_catch.
172
173    Any data associated with the exception must currently be handled by
174    some external mechanism maintained in the frontend.  For example,
175    the C++ exception mechanism passes an arbitrary value along with
176    the exception, and this is handled in the C++ frontend by using a
177    global variable to hold the value. (This will be changing in the
178    future.)
179
180    The mechanism in C++ for handling data associated with the
181    exception is clearly not thread-safe. For a thread-based
182    environment, another mechanism must be used (possibly using a
183    per-thread allocation mechanism if the size of the area that needs
184    to be allocated isn't known at compile time.)
185
186    Internally-generated exception regions (cleanups) are marked by
187    calling expand_eh_region_start to mark the start of the region,
188    and expand_eh_region_end (handler) is used to both designate the
189    end of the region and to associate a specified handler/cleanup with
190    the region. The rtl code in HANDLER will be invoked whenever an
191    exception occurs in the region between the calls to
192    expand_eh_region_start and expand_eh_region_end. After HANDLER is
193    executed, additional code is emitted to handle rethrowing the
194    exception to the outer exception handler. The code for HANDLER will
195    be emitted at the end of the function.
196
197    TARGET_EXPRs can also be used to designate exception regions. A
198    TARGET_EXPR gives an unwind-protect style interface commonly used
199    in functional languages such as LISP. The associated expression is
200    evaluated, and whether or not it (or any of the functions that it
201    calls) throws an exception, the protect expression is always
202    invoked. This implementation takes care of the details of
203    associating an exception table entry with the expression and
204    generating the necessary code (it actually emits the protect
205    expression twice, once for normal flow and once for the exception
206    case). As for the other handlers, the code for the exception case
207    will be emitted at the end of the function.
208
209    Cleanups can also be specified by using add_partial_entry (handler)
210    and end_protect_partials. add_partial_entry creates the start of
211    a new exception region; HANDLER will be invoked if an exception is
212    thrown with the context of the region between the calls to
213    add_partial_entry and end_protect_partials. end_protect_partials is
214    used to mark the end of these regions. add_partial_entry can be
215    called as many times as needed before calling end_protect_partials.
216    However, end_protect_partials should only be invoked once for each
217    group of calls to add_partial_entry as the entries are queued
218    and all of the outstanding entries are processed simultaneously
219    when end_protect_partials is invoked. Similarly to the other
220    handlers, the code for HANDLER will be emitted at the end of the
221    function.
222
223    The generated RTL for an exception region includes
224    NOTE_INSN_EH_REGION_BEG and NOTE_INSN_EH_REGION_END notes that mark
225    the start and end of the exception region. A unique label is also
226    generated at the start of the exception region, which is available
227    by looking at the ehstack variable. The topmost entry corresponds
228    to the current region.
229
230    In the current implementation, an exception can only be thrown from
231    a function call (since the mechanism used to actually throw an
232    exception involves calling __throw).  If an exception region is
233    created but no function calls occur within that region, the region
234    can be safely optimized away (along with its exception handlers)
235    since no exceptions can ever be caught in that region.  This
236    optimization is performed unless -fasynchronous-exceptions is
237    given.  If the user wishes to throw from a signal handler, or other
238    asynchronous place, -fasynchronous-exceptions should be used when
239    compiling for maximally correct code, at the cost of additional
240    exception regions.  Using -fasynchronous-exceptions only produces
241    code that is reasonably safe in such situations, but a correct
242    program cannot rely upon this working.  It can be used in failsafe
243    code, where trying to continue on, and proceeding with potentially
244    incorrect results is better than halting the program.
245
246
247    Walking the stack:
248
249    The stack is walked by starting with a pointer to the current
250    frame, and finding the pointer to the callers frame.  The unwind info
251    tells __throw how to find it.
252
253    Unwinding the stack:
254
255    When we use the term unwinding the stack, we mean undoing the
256    effects of the function prologue in a controlled fashion so that we
257    still have the flow of control.  Otherwise, we could just return
258    (jump to the normal end of function epilogue).
259
260    This is done in __throw in libgcc2.c when we know that a handler exists
261    in a frame higher up the call stack than its immediate caller.
262
263    To unwind, we find the unwind data associated with the frame, if any.
264    If we don't find any, we call the library routine __terminate.  If we do
265    find it, we use the information to copy the saved register values from
266    that frame into the register save area in the frame for __throw, return
267    into a stub which updates the stack pointer, and jump to the handler.
268    The normal function epilogue for __throw handles restoring the saved
269    values into registers.
270
271    When unwinding, we use this method if we know it will
272    work (if DWARF2_UNWIND_INFO is defined).  Otherwise, we know that
273    an inline unwinder will have been emitted for any function that
274    __unwind_function cannot unwind.  The inline unwinder appears as a
275    normal exception handler for the entire function, for any function
276    that we know cannot be unwound by __unwind_function.  We inform the
277    compiler of whether a function can be unwound with
278    __unwind_function by having DOESNT_NEED_UNWINDER evaluate to true
279    when the unwinder isn't needed.  __unwind_function is used as an
280    action of last resort.  If no other method can be used for
281    unwinding, __unwind_function is used.  If it cannot unwind, it
282    should call __terminate.
283
284    By default, if the target-specific backend doesn't supply a definition
285    for __unwind_function and doesn't support DWARF2_UNWIND_INFO, inlined
286    unwinders will be used instead. The main tradeoff here is in text space
287    utilization.  Obviously, if inline unwinders have to be generated
288    repeatedly, this uses much more space than if a single routine is used.
289
290    However, it is simply not possible on some platforms to write a
291    generalized routine for doing stack unwinding without having some
292    form of additional data associated with each function.  The current
293    implementation can encode this data in the form of additional
294    machine instructions or as static data in tabular form.  The later
295    is called the unwind data.
296
297    The backend macro DOESNT_NEED_UNWINDER is used to conditionalize whether
298    or not per-function unwinders are needed. If DOESNT_NEED_UNWINDER is
299    defined and has a non-zero value, a per-function unwinder is not emitted
300    for the current function.  If the static unwind data is supported, then
301    a per-function unwinder is not emitted.
302
303    On some platforms it is possible that neither __unwind_function
304    nor inlined unwinders are available. For these platforms it is not
305    possible to throw through a function call, and abort will be
306    invoked instead of performing the throw. 
307
308    The reason the unwind data may be needed is that on some platforms
309    the order and types of data stored on the stack can vary depending
310    on the type of function, its arguments and returned values, and the
311    compilation options used (optimization versus non-optimization,
312    -fomit-frame-pointer, processor variations, etc).
313
314    Unfortunately, this also means that throwing through functions that
315    aren't compiled with exception handling support will still not be
316    possible on some platforms. This problem is currently being
317    investigated, but no solutions have been found that do not imply
318    some unacceptable performance penalties.
319
320    Future directions:
321
322    Currently __throw makes no differentiation between cleanups and
323    user-defined exception regions. While this makes the implementation
324    simple, it also implies that it is impossible to determine if a
325    user-defined exception handler exists for a given exception without
326    completely unwinding the stack in the process. This is undesirable
327    from the standpoint of debugging, as ideally it would be possible
328    to trap unhandled exceptions in the debugger before the process of
329    unwinding has even started.
330
331    This problem can be solved by marking user-defined handlers in a
332    special way (probably by adding additional bits to exception_table_list).
333    A two-pass scheme could then be used by __throw to iterate
334    through the table. The first pass would search for a relevant
335    user-defined handler for the current context of the throw, and if
336    one is found, the second pass would then invoke all needed cleanups
337    before jumping to the user-defined handler.
338
339    Many languages (including C++ and Ada) make execution of a
340    user-defined handler conditional on the "type" of the exception
341    thrown. (The type of the exception is actually the type of the data
342    that is thrown with the exception.) It will thus be necessary for
343    __throw to be able to determine if a given user-defined
344    exception handler will actually be executed, given the type of
345    exception.
346
347    One scheme is to add additional information to exception_table_list
348    as to the types of exceptions accepted by each handler. __throw
349    can do the type comparisons and then determine if the handler is
350    actually going to be executed.
351
352    There is currently no significant level of debugging support
353    available, other than to place a breakpoint on __throw. While
354    this is sufficient in most cases, it would be helpful to be able to
355    know where a given exception was going to be thrown to before it is
356    actually thrown, and to be able to choose between stopping before
357    every exception region (including cleanups), or just user-defined
358    exception regions. This should be possible to do in the two-pass
359    scheme by adding additional labels to __throw for appropriate
360    breakpoints, and additional debugger commands could be added to
361    query various state variables to determine what actions are to be
362    performed next.
363
364    Another major problem that is being worked on is the issue with stack
365    unwinding on various platforms. Currently the only platforms that have
366    support for the generation of a generic unwinder are the SPARC and MIPS.
367    All other ports require per-function unwinders, which produce large
368    amounts of code bloat.
369
370    For setjmp/longjmp based exception handling, some of the details
371    are as above, but there are some additional details.  This section
372    discusses the details.
373
374    We don't use NOTE_INSN_EH_REGION_{BEG,END} pairs.  We don't
375    optimize EH regions yet.  We don't have to worry about machine
376    specific issues with unwinding the stack, as we rely upon longjmp
377    for all the machine specific details.  There is no variable context
378    of a throw, just the one implied by the dynamic handler stack
379    pointed to by the dynamic handler chain.  There is no exception
380    table, and no calls to __register_exceptions.  __sjthrow is used
381    instead of __throw, and it works by using the dynamic handler
382    chain, and longjmp.  -fasynchronous-exceptions has no effect, as
383    the elimination of trivial exception regions is not yet performed.
384
385    A frontend can set protect_cleanup_actions_with_terminate when all
386    the cleanup actions should be protected with an EH region that
387    calls terminate when an unhandled exception is throw.  C++ does
388    this, Ada does not.  */
389
390
391 #include "config.h"
392 #include "defaults.h"
393 #include "eh-common.h"
394 #include "system.h"
395 #include "rtl.h"
396 #include "tree.h"
397 #include "flags.h"
398 #include "except.h"
399 #include "function.h"
400 #include "insn-flags.h"
401 #include "expr.h"
402 #include "insn-codes.h"
403 #include "regs.h"
404 #include "hard-reg-set.h"
405 #include "insn-config.h"
406 #include "recog.h"
407 #include "output.h"
408 #include "toplev.h"
409 #include "intl.h"
410 #include "obstack.h"
411
412 /* One to use setjmp/longjmp method of generating code for exception
413    handling.  */
414
415 int exceptions_via_longjmp = 2;
416
417 /* One to enable asynchronous exception support.  */
418
419 int asynchronous_exceptions = 0;
420
421 /* One to protect cleanup actions with a handler that calls
422    __terminate, zero otherwise.  */
423
424 int protect_cleanup_actions_with_terminate;
425
426 /* A list of labels used for exception handlers.  Created by
427    find_exception_handler_labels for the optimization passes.  */
428
429 rtx exception_handler_labels;
430
431 /* Keeps track of the label used as the context of a throw to rethrow an
432    exception to the outer exception region.  */
433
434 struct label_node *outer_context_label_stack = NULL;
435
436 /* Pseudos used to hold exception return data in the interim between
437    __builtin_eh_return and the end of the function.  */
438
439 static rtx eh_return_context;
440 static rtx eh_return_stack_adjust;
441 static rtx eh_return_handler;
442
443 /* This is used for targets which can call rethrow with an offset instead
444    of an address. This is subtracted from the rethrow label we are
445    interested in. */
446
447 static rtx first_rethrow_symbol = NULL_RTX;
448 static rtx final_rethrow = NULL_RTX;
449 static rtx last_rethrow_symbol = NULL_RTX;
450
451
452 /* Prototypes for local functions.  */
453
454 static void push_eh_entry       PROTO((struct eh_stack *));
455 static struct eh_entry * pop_eh_entry           PROTO((struct eh_stack *));
456 static void enqueue_eh_entry    PROTO((struct eh_queue *, struct eh_entry *));
457 static struct eh_entry * dequeue_eh_entry       PROTO((struct eh_queue *));
458 static rtx call_get_eh_context  PROTO((void));
459 static void start_dynamic_cleanup               PROTO((tree, tree));
460 static void start_dynamic_handler               PROTO((void));
461 static void expand_rethrow      PROTO((rtx));
462 static void output_exception_table_entry        PROTO((FILE *, int));
463 static int can_throw            PROTO((rtx));
464 static rtx scan_region          PROTO((rtx, int, int *));
465 static void eh_regs             PROTO((rtx *, rtx *, rtx *, int));
466 static void set_insn_eh_region  PROTO((rtx *, int));
467 #ifdef DONT_USE_BUILTIN_SETJMP
468 static void jumpif_rtx          PROTO((rtx, rtx));
469 #endif
470
471 rtx expand_builtin_return_addr  PROTO((enum built_in_function, int, rtx));
472 \f
473 /* Various support routines to manipulate the various data structures
474    used by the exception handling code.  */
475
476 extern struct obstack permanent_obstack;
477
478 /* Generate a SYMBOL_REF for rethrow to use */
479 static rtx
480 create_rethrow_ref (region_num)
481      int region_num;
482 {
483   rtx def;
484   char *ptr;
485   char buf[60];
486
487   push_obstacks_nochange ();
488   end_temporary_allocation ();
489
490   ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", region_num);
491   ptr = (char *) obstack_copy0 (&permanent_obstack, buf, strlen (buf));
492   def = gen_rtx_SYMBOL_REF (Pmode, ptr);
493   SYMBOL_REF_NEED_ADJUST (def) = 1;
494
495   pop_obstacks ();
496   return def;
497 }
498
499 /* Push a label entry onto the given STACK.  */
500
501 void
502 push_label_entry (stack, rlabel, tlabel)
503      struct label_node **stack;
504      rtx rlabel;
505      tree tlabel;
506 {
507   struct label_node *newnode
508     = (struct label_node *) xmalloc (sizeof (struct label_node));
509
510   if (rlabel)
511     newnode->u.rlabel = rlabel;
512   else
513     newnode->u.tlabel = tlabel;
514   newnode->chain = *stack;
515   *stack = newnode;
516 }
517
518 /* Pop a label entry from the given STACK.  */
519
520 rtx
521 pop_label_entry (stack)
522      struct label_node **stack;
523 {
524   rtx label;
525   struct label_node *tempnode;
526
527   if (! *stack)
528     return NULL_RTX;
529
530   tempnode = *stack;
531   label = tempnode->u.rlabel;
532   *stack = (*stack)->chain;
533   free (tempnode);
534
535   return label;
536 }
537
538 /* Return the top element of the given STACK.  */
539
540 tree
541 top_label_entry (stack)
542      struct label_node **stack;
543 {
544   if (! *stack)
545     return NULL_TREE;
546
547   return (*stack)->u.tlabel;
548 }
549
550 /* get an exception label. These must be on the permanent obstack */
551
552 rtx
553 gen_exception_label ()
554 {
555   rtx lab;
556   lab = gen_label_rtx ();
557   return lab;
558 }
559
560 /* Push a new eh_node entry onto STACK.  */
561
562 static void
563 push_eh_entry (stack)
564      struct eh_stack *stack;
565 {
566   struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
567   struct eh_entry *entry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry));
568
569   rtx rlab = gen_exception_label ();
570   entry->finalization = NULL_TREE;
571   entry->label_used = 0;
572   entry->exception_handler_label = rlab;
573   entry->false_label = NULL_RTX;
574   if (! flag_new_exceptions)
575     entry->outer_context = gen_label_rtx ();
576   else
577     entry->outer_context = create_rethrow_ref (CODE_LABEL_NUMBER (rlab));
578   entry->rethrow_label = entry->outer_context;
579
580   node->entry = entry;
581   node->chain = stack->top;
582   stack->top = node;
583 }
584
585 /* push an existing entry onto a stack. */
586 static void
587 push_entry (stack, entry)
588      struct eh_stack *stack;
589      struct eh_entry *entry;
590 {
591   struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
592   node->entry = entry;
593   node->chain = stack->top;
594   stack->top = node;
595 }
596
597 /* Pop an entry from the given STACK.  */
598
599 static struct eh_entry *
600 pop_eh_entry (stack)
601      struct eh_stack *stack;
602 {
603   struct eh_node *tempnode;
604   struct eh_entry *tempentry;
605   
606   tempnode = stack->top;
607   tempentry = tempnode->entry;
608   stack->top = stack->top->chain;
609   free (tempnode);
610
611   return tempentry;
612 }
613
614 /* Enqueue an ENTRY onto the given QUEUE.  */
615
616 static void
617 enqueue_eh_entry (queue, entry)
618      struct eh_queue *queue;
619      struct eh_entry *entry;
620 {
621   struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
622
623   node->entry = entry;
624   node->chain = NULL;
625
626   if (queue->head == NULL)
627     {
628       queue->head = node;
629     }
630   else
631     {
632       queue->tail->chain = node;
633     }
634   queue->tail = node;
635 }
636
637 /* Dequeue an entry from the given QUEUE.  */
638
639 static struct eh_entry *
640 dequeue_eh_entry (queue)
641      struct eh_queue *queue;
642 {
643   struct eh_node *tempnode;
644   struct eh_entry *tempentry;
645
646   if (queue->head == NULL)
647     return NULL;
648
649   tempnode = queue->head;
650   queue->head = queue->head->chain;
651
652   tempentry = tempnode->entry;
653   free (tempnode);
654
655   return tempentry;
656 }
657
658 static void
659 receive_exception_label (handler_label)
660      rtx handler_label;
661 {
662   emit_label (handler_label);
663   
664 #ifdef HAVE_exception_receiver
665   if (! exceptions_via_longjmp)
666     if (HAVE_exception_receiver)
667       emit_insn (gen_exception_receiver ());
668 #endif
669
670 #ifdef HAVE_nonlocal_goto_receiver
671   if (! exceptions_via_longjmp)
672     if (HAVE_nonlocal_goto_receiver)
673       emit_insn (gen_nonlocal_goto_receiver ());
674 #endif
675 }
676
677
678 struct func_eh_entry 
679 {
680   int range_number;   /* EH region number from EH NOTE insn's */
681   rtx rethrow_label;  /* Label for rethrow */
682   struct handler_info *handlers;
683 };
684
685
686 /* table of function eh regions */
687 static struct func_eh_entry *function_eh_regions = NULL;
688 static int num_func_eh_entries = 0;
689 static int current_func_eh_entry = 0;
690
691 #define SIZE_FUNC_EH(X)   (sizeof (struct func_eh_entry) * X)
692
693 /* Add a new eh_entry for this function, and base it off of the information
694    in the EH_ENTRY parameter. A NULL parameter is invalid. 
695    OUTER_CONTEXT is a label which is used for rethrowing. The number
696    returned is an number which uniquely identifies this exception range. */
697
698 static int 
699 new_eh_region_entry (note_eh_region, rethrow) 
700      int note_eh_region;
701      rtx rethrow;
702 {
703   if (current_func_eh_entry == num_func_eh_entries) 
704     {
705       if (num_func_eh_entries == 0)
706         {
707           function_eh_regions = 
708                         (struct func_eh_entry *) malloc (SIZE_FUNC_EH (50));
709           num_func_eh_entries = 50;
710         }
711       else
712         {
713           num_func_eh_entries  = num_func_eh_entries * 3 / 2;
714           function_eh_regions = (struct func_eh_entry *) 
715             realloc (function_eh_regions, SIZE_FUNC_EH (num_func_eh_entries));
716         }
717     }
718   function_eh_regions[current_func_eh_entry].range_number = note_eh_region;
719   if (rethrow == NULL_RTX)
720     function_eh_regions[current_func_eh_entry].rethrow_label = 
721                                           create_rethrow_ref (note_eh_region);
722   else
723     function_eh_regions[current_func_eh_entry].rethrow_label = rethrow;
724   function_eh_regions[current_func_eh_entry].handlers = NULL;
725
726   return current_func_eh_entry++;
727 }
728
729 /* Add new handler information to an exception range. The  first parameter
730    specifies the range number (returned from new_eh_entry()). The second
731    parameter specifies the handler.  By default the handler is inserted at
732    the end of the list. A handler list may contain only ONE NULL_TREE
733    typeinfo entry. Regardless where it is positioned, a NULL_TREE entry
734    is always output as the LAST handler in the exception table for a region. */
735
736 void 
737 add_new_handler (region, newhandler)
738      int region;
739      struct handler_info *newhandler;
740 {
741   struct handler_info *last;
742
743   newhandler->next = NULL;
744   last = function_eh_regions[region].handlers;
745   if (last == NULL)
746     function_eh_regions[region].handlers = newhandler;
747   else 
748     {
749       for ( ; ; last = last->next)
750         {
751           if (last->type_info == CATCH_ALL_TYPE)
752             pedwarn ("additional handler after ...");
753           if (last->next == NULL)
754             break;
755         }
756       last->next = newhandler;
757     }
758 }
759
760 /* Remove a handler label. The handler label is being deleted, so all
761    regions which reference this handler should have it removed from their
762    list of possible handlers. Any region which has the final handler
763    removed can be deleted. */
764
765 void remove_handler (removing_label)
766      rtx removing_label;
767 {
768   struct handler_info *handler, *last;
769   int x;
770   for (x = 0 ; x < current_func_eh_entry; ++x)
771     {
772       last = NULL;
773       handler = function_eh_regions[x].handlers;
774       for ( ; handler; last = handler, handler = handler->next)
775         if (handler->handler_label == removing_label)
776           {
777             if (last)
778               {
779                 last->next = handler->next;
780                 handler = last;
781               }
782             else
783               function_eh_regions[x].handlers = handler->next;
784           }
785     }
786 }
787
788 /* This function will return a malloc'd pointer to an array of 
789    void pointer representing the runtime match values that 
790    currently exist in all regions. */
791
792 int 
793 find_all_handler_type_matches (array)
794   void ***array;
795 {
796   struct handler_info *handler, *last;
797   int x,y;
798   void *val;
799   void **ptr;
800   int max_ptr;
801   int n_ptr = 0;
802
803   *array = NULL;
804
805   if (!doing_eh (0) || ! flag_new_exceptions)
806     return 0;
807
808   max_ptr = 100;
809   ptr = (void **)malloc (max_ptr * sizeof (void *));
810
811   if (ptr == NULL)
812     return 0;
813
814   for (x = 0 ; x < current_func_eh_entry; x++)
815     {
816       last = NULL;
817       handler = function_eh_regions[x].handlers;
818       for ( ; handler; last = handler, handler = handler->next)
819         {
820           val = handler->type_info;
821           if (val != NULL && val != CATCH_ALL_TYPE)
822             {
823               /* See if this match value has already been found. */
824               for (y = 0; y < n_ptr; y++)
825                 if (ptr[y] == val)
826                   break;
827
828               /* If we break early, we already found this value. */
829               if (y < n_ptr)
830                 continue;
831
832               /* Do we need to allocate more space? */
833               if (n_ptr >= max_ptr) 
834                 {
835                   max_ptr += max_ptr / 2;
836                   ptr = (void **)realloc (ptr, max_ptr * sizeof (void *));
837                   if (ptr == NULL)
838                     return 0;
839                 }
840               ptr[n_ptr] = val;
841               n_ptr++;
842             }
843         }
844     }
845   *array = ptr;
846   return n_ptr;
847 }
848
849 /* Create a new handler structure initialized with the handler label and
850    typeinfo fields passed in. */
851
852 struct handler_info *
853 get_new_handler (handler, typeinfo)
854      rtx handler;
855      void *typeinfo;
856 {
857   struct handler_info* ptr;
858   ptr = (struct handler_info *) malloc (sizeof (struct handler_info));
859   ptr->handler_label = handler;
860   ptr->handler_number = CODE_LABEL_NUMBER (handler);
861   ptr->type_info = typeinfo;
862   ptr->next = NULL;
863
864   return ptr;
865 }
866
867
868
869 /* Find the index in function_eh_regions associated with a NOTE region. If
870    the region cannot be found, a -1 is returned. This should never happen! */
871
872 int 
873 find_func_region (insn_region)
874      int insn_region;
875 {
876   int x;
877   for (x = 0; x < current_func_eh_entry; x++)
878     if (function_eh_regions[x].range_number == insn_region)
879       return x;
880
881   return -1;
882 }
883
884 /* Get a pointer to the first handler in an exception region's list. */
885
886 struct handler_info *
887 get_first_handler (region)
888      int region;
889 {
890   return function_eh_regions[find_func_region (region)].handlers;
891 }
892
893 /* Clean out the function_eh_region table and free all memory */
894
895 static void
896 clear_function_eh_region ()
897 {
898   int x;
899   struct handler_info *ptr, *next;
900   for (x = 0; x < current_func_eh_entry; x++)
901     for (ptr = function_eh_regions[x].handlers; ptr != NULL; ptr = next)
902       {
903         next = ptr->next;
904         free (ptr);
905       }
906   free (function_eh_regions);
907   num_func_eh_entries  = 0;
908   current_func_eh_entry = 0;
909 }
910
911 /* Make a duplicate of an exception region by copying all the handlers
912    for an exception region. Return the new handler index. The final
913    parameter is a routine which maps old labels to new ones. */
914
915 int 
916 duplicate_eh_handlers (old_note_eh_region, new_note_eh_region, map)
917      int old_note_eh_region, new_note_eh_region;
918      rtx (*map) PARAMS ((rtx));
919 {
920   struct handler_info *ptr, *new_ptr;
921   int new_region, region;
922
923   region = find_func_region (old_note_eh_region);
924   if (region == -1)
925     fatal ("Cannot duplicate non-existant exception region.");
926
927   /* duplicate_eh_handlers may have been called during a symbol remap. */
928   new_region = find_func_region (new_note_eh_region);
929   if (new_region != -1)
930     return (new_region);
931
932   new_region = new_eh_region_entry (new_note_eh_region, NULL_RTX);
933
934   ptr = function_eh_regions[region].handlers;
935
936   for ( ; ptr; ptr = ptr->next) 
937     {
938       new_ptr = get_new_handler (map (ptr->handler_label), ptr->type_info);
939       add_new_handler (new_region, new_ptr);
940     }
941
942   return new_region;
943 }
944
945
946 /* Given a rethrow symbol, find the EH region number this is for. */
947 int 
948 eh_region_from_symbol (sym)
949      rtx sym;
950 {
951   int x;
952   if (sym == last_rethrow_symbol)
953     return 1;
954   for (x = 0; x < current_func_eh_entry; x++)
955     if (function_eh_regions[x].rethrow_label == sym)
956       return function_eh_regions[x].range_number;
957   return -1;
958 }
959
960
961 /* When inlining/unrolling, we have to map the symbols passed to
962    __rethrow as well. This performs the remap. If a symbol isn't foiund,
963    the original one is returned. This is not an efficient routine,
964    so don't call it on everything!! */
965 rtx 
966 rethrow_symbol_map (sym, map)
967      rtx sym;
968      rtx (*map) PARAMS ((rtx));
969 {
970   int x, y;
971   for (x = 0; x < current_func_eh_entry; x++)
972     if (function_eh_regions[x].rethrow_label == sym)
973       {
974         /* We've found the original region, now lets determine which region
975            this now maps to. */
976         rtx l1 = function_eh_regions[x].handlers->handler_label;
977         rtx l2 = map (l1);
978         y = CODE_LABEL_NUMBER (l2); /* This is the new region number */
979         x = find_func_region (y);  /* Get the new permanent region */
980         if (x == -1)  /* Hmm, Doesn't exist yet */
981           {
982             x = duplicate_eh_handlers (CODE_LABEL_NUMBER (l1), y, map);
983             /* Since we're mapping it, it must be used. */
984             SYMBOL_REF_USED (function_eh_regions[x].rethrow_label) = 1;
985           }
986         return function_eh_regions[x].rethrow_label;
987       }
988   return sym;
989 }
990
991 int 
992 rethrow_used (region)
993      int region;
994 {
995   if (flag_new_exceptions)
996     {
997       rtx lab = function_eh_regions[find_func_region (region)].rethrow_label;
998       return (SYMBOL_REF_USED (lab));
999     }
1000   return 0;
1001 }
1002
1003 \f
1004 /* Routine to see if exception handling is turned on.
1005    DO_WARN is non-zero if we want to inform the user that exception
1006    handling is turned off. 
1007
1008    This is used to ensure that -fexceptions has been specified if the
1009    compiler tries to use any exception-specific functions.  */
1010
1011 int
1012 doing_eh (do_warn)
1013      int do_warn;
1014 {
1015   if (! flag_exceptions)
1016     {
1017       static int warned = 0;
1018       if (! warned && do_warn)
1019         {
1020           error ("exception handling disabled, use -fexceptions to enable");
1021           warned = 1;
1022         }
1023       return 0;
1024     }
1025   return 1;
1026 }
1027
1028 /* Given a return address in ADDR, determine the address we should use
1029    to find the corresponding EH region.  */
1030
1031 rtx
1032 eh_outer_context (addr)
1033      rtx addr;
1034 {
1035   /* First mask out any unwanted bits.  */
1036 #ifdef MASK_RETURN_ADDR
1037   expand_and (addr, MASK_RETURN_ADDR, addr);
1038 #endif
1039
1040   /* Then adjust to find the real return address.  */
1041 #if defined (RETURN_ADDR_OFFSET)
1042   addr = plus_constant (addr, RETURN_ADDR_OFFSET);
1043 #endif
1044
1045   return addr;
1046 }
1047
1048 /* Start a new exception region for a region of code that has a
1049    cleanup action and push the HANDLER for the region onto
1050    protect_list. All of the regions created with add_partial_entry
1051    will be ended when end_protect_partials is invoked.  */
1052
1053 void
1054 add_partial_entry (handler)
1055      tree handler;
1056 {
1057   expand_eh_region_start ();
1058
1059   /* Make sure the entry is on the correct obstack.  */
1060   push_obstacks_nochange ();
1061   resume_temporary_allocation ();
1062
1063   /* Because this is a cleanup action, we may have to protect the handler
1064      with __terminate.  */
1065   handler = protect_with_terminate (handler);
1066
1067   protect_list = tree_cons (NULL_TREE, handler, protect_list);
1068   pop_obstacks ();
1069 }
1070
1071 /* Emit code to get EH context to current function.  */
1072
1073 static rtx
1074 call_get_eh_context ()
1075 {
1076   static tree fn;
1077   tree expr;
1078
1079   if (fn == NULL_TREE)
1080     {
1081       tree fntype;
1082       fn = get_identifier ("__get_eh_context");
1083       push_obstacks_nochange ();
1084       end_temporary_allocation ();
1085       fntype = build_pointer_type (build_pointer_type
1086                                    (build_pointer_type (void_type_node)));
1087       fntype = build_function_type (fntype, NULL_TREE);
1088       fn = build_decl (FUNCTION_DECL, fn, fntype);
1089       DECL_EXTERNAL (fn) = 1;
1090       TREE_PUBLIC (fn) = 1;
1091       DECL_ARTIFICIAL (fn) = 1;
1092       TREE_READONLY (fn) = 1;
1093       make_decl_rtl (fn, NULL_PTR, 1);
1094       assemble_external (fn);
1095       pop_obstacks ();
1096     }
1097
1098   expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
1099   expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
1100                 expr, NULL_TREE, NULL_TREE);
1101   TREE_SIDE_EFFECTS (expr) = 1;
1102
1103   return copy_to_reg (expand_expr (expr, NULL_RTX, VOIDmode, 0));
1104 }
1105
1106 /* Get a reference to the EH context.
1107    We will only generate a register for the current function EH context here,
1108    and emit a USE insn to mark that this is a EH context register.
1109
1110    Later, emit_eh_context will emit needed call to __get_eh_context
1111    in libgcc2, and copy the value to the register we have generated. */
1112
1113 rtx
1114 get_eh_context ()
1115 {
1116   if (current_function_ehc == 0)
1117     {
1118       rtx insn;
1119
1120       current_function_ehc = gen_reg_rtx (Pmode);
1121       
1122       insn = gen_rtx_USE (GET_MODE (current_function_ehc),
1123                           current_function_ehc);
1124       insn = emit_insn_before (insn, get_first_nonparm_insn ());
1125
1126       REG_NOTES (insn)
1127         = gen_rtx_EXPR_LIST (REG_EH_CONTEXT, current_function_ehc,
1128                              REG_NOTES (insn));
1129     }
1130   return current_function_ehc;
1131 }
1132      
1133 /* Get a reference to the dynamic handler chain.  It points to the
1134    pointer to the next element in the dynamic handler chain.  It ends
1135    when there are no more elements in the dynamic handler chain, when
1136    the value is &top_elt from libgcc2.c.  Immediately after the
1137    pointer, is an area suitable for setjmp/longjmp when
1138    DONT_USE_BUILTIN_SETJMP is defined, and an area suitable for
1139    __builtin_setjmp/__builtin_longjmp when DONT_USE_BUILTIN_SETJMP
1140    isn't defined. */
1141
1142 rtx
1143 get_dynamic_handler_chain ()
1144 {
1145   rtx ehc, dhc, result;
1146
1147   ehc = get_eh_context ();
1148
1149   /* This is the offset of dynamic_handler_chain in the eh_context struct
1150      declared in eh-common.h. If its location is change, change this offset */
1151   dhc = plus_constant (ehc, POINTER_SIZE / BITS_PER_UNIT);
1152
1153   result = copy_to_reg (dhc);
1154
1155   /* We don't want a copy of the dcc, but rather, the single dcc.  */
1156   return gen_rtx_MEM (Pmode, result);
1157 }
1158
1159 /* Get a reference to the dynamic cleanup chain.  It points to the
1160    pointer to the next element in the dynamic cleanup chain.
1161    Immediately after the pointer, are two Pmode variables, one for a
1162    pointer to a function that performs the cleanup action, and the
1163    second, the argument to pass to that function.  */
1164
1165 rtx
1166 get_dynamic_cleanup_chain ()
1167 {
1168   rtx dhc, dcc, result;
1169
1170   dhc = get_dynamic_handler_chain ();
1171   dcc = plus_constant (dhc, POINTER_SIZE / BITS_PER_UNIT);
1172
1173   result = copy_to_reg (dcc);
1174
1175   /* We don't want a copy of the dcc, but rather, the single dcc.  */
1176   return gen_rtx_MEM (Pmode, result);
1177 }
1178
1179 #ifdef DONT_USE_BUILTIN_SETJMP
1180 /* Generate code to evaluate X and jump to LABEL if the value is nonzero.
1181    LABEL is an rtx of code CODE_LABEL, in this function.  */
1182
1183 static void
1184 jumpif_rtx (x, label)
1185      rtx x;
1186      rtx label;
1187 {
1188   jumpif (make_tree (type_for_mode (GET_MODE (x), 0), x), label);
1189 }
1190 #endif
1191
1192 /* Start a dynamic cleanup on the EH runtime dynamic cleanup stack.
1193    We just need to create an element for the cleanup list, and push it
1194    into the chain.
1195
1196    A dynamic cleanup is a cleanup action implied by the presence of an
1197    element on the EH runtime dynamic cleanup stack that is to be
1198    performed when an exception is thrown.  The cleanup action is
1199    performed by __sjthrow when an exception is thrown.  Only certain
1200    actions can be optimized into dynamic cleanup actions.  For the
1201    restrictions on what actions can be performed using this routine,
1202    see expand_eh_region_start_tree.  */
1203
1204 static void
1205 start_dynamic_cleanup (func, arg)
1206      tree func;
1207      tree arg;
1208 {
1209   rtx dcc;
1210   rtx new_func, new_arg;
1211   rtx x, buf;
1212   int size;
1213
1214   /* We allocate enough room for a pointer to the function, and
1215      one argument.  */
1216   size = 2;
1217
1218   /* XXX, FIXME: The stack space allocated this way is too long lived,
1219      but there is no allocation routine that allocates at the level of
1220      the last binding contour.  */
1221   buf = assign_stack_local (BLKmode,
1222                             GET_MODE_SIZE (Pmode)*(size+1),
1223                             0);
1224
1225   buf = change_address (buf, Pmode, NULL_RTX);
1226
1227   /* Store dcc into the first word of the newly allocated buffer.  */
1228
1229   dcc = get_dynamic_cleanup_chain ();
1230   emit_move_insn (buf, dcc);
1231
1232   /* Store func and arg into the cleanup list element.  */
1233
1234   new_func = gen_rtx_MEM (Pmode, plus_constant (XEXP (buf, 0),
1235                                                 GET_MODE_SIZE (Pmode)));
1236   new_arg = gen_rtx_MEM (Pmode, plus_constant (XEXP (buf, 0),
1237                                                GET_MODE_SIZE (Pmode)*2));
1238   x = expand_expr (func, new_func, Pmode, 0);
1239   if (x != new_func)
1240     emit_move_insn (new_func, x);
1241
1242   x = expand_expr (arg, new_arg, Pmode, 0);
1243   if (x != new_arg)
1244     emit_move_insn (new_arg, x);
1245
1246   /* Update the cleanup chain.  */
1247
1248   x = force_operand (XEXP (buf, 0), dcc);
1249   if (x != dcc)
1250     emit_move_insn (dcc, x);
1251 }
1252
1253 /* Emit RTL to start a dynamic handler on the EH runtime dynamic
1254    handler stack.  This should only be used by expand_eh_region_start
1255    or expand_eh_region_start_tree.  */
1256
1257 static void
1258 start_dynamic_handler ()
1259 {
1260   rtx dhc, dcc;
1261   rtx x, arg, buf;
1262   int size;
1263
1264 #ifndef DONT_USE_BUILTIN_SETJMP
1265   /* The number of Pmode words for the setjmp buffer, when using the
1266      builtin setjmp/longjmp, see expand_builtin, case
1267      BUILT_IN_LONGJMP.  */
1268   size = 5;
1269 #else
1270 #ifdef JMP_BUF_SIZE
1271   size = JMP_BUF_SIZE;
1272 #else
1273   /* Should be large enough for most systems, if it is not,
1274      JMP_BUF_SIZE should be defined with the proper value.  It will
1275      also tend to be larger than necessary for most systems, a more
1276      optimal port will define JMP_BUF_SIZE.  */
1277   size = FIRST_PSEUDO_REGISTER+2;
1278 #endif
1279 #endif
1280   /* XXX, FIXME: The stack space allocated this way is too long lived,
1281      but there is no allocation routine that allocates at the level of
1282      the last binding contour.  */
1283   arg = assign_stack_local (BLKmode,
1284                             GET_MODE_SIZE (Pmode)*(size+1),
1285                             0);
1286
1287   arg = change_address (arg, Pmode, NULL_RTX);
1288
1289   /* Store dhc into the first word of the newly allocated buffer.  */
1290
1291   dhc = get_dynamic_handler_chain ();
1292   dcc = gen_rtx_MEM (Pmode, plus_constant (XEXP (arg, 0),
1293                                            GET_MODE_SIZE (Pmode)));
1294   emit_move_insn (arg, dhc);
1295
1296   /* Zero out the start of the cleanup chain.  */
1297   emit_move_insn (dcc, const0_rtx);
1298
1299   /* The jmpbuf starts two words into the area allocated.  */
1300   buf = plus_constant (XEXP (arg, 0), GET_MODE_SIZE (Pmode)*2);
1301
1302 #ifdef DONT_USE_BUILTIN_SETJMP
1303   x = emit_library_call_value (setjmp_libfunc, NULL_RTX, 1, SImode, 1,
1304                                buf, Pmode);
1305   /* If we come back here for a catch, transfer control to the handler.  */
1306   jumpif_rtx (x, ehstack.top->entry->exception_handler_label);
1307 #else
1308   {
1309     /* A label to continue execution for the no exception case.  */
1310     rtx noex = gen_label_rtx();
1311     x = expand_builtin_setjmp (buf, NULL_RTX, noex,
1312                                ehstack.top->entry->exception_handler_label);
1313     emit_label (noex);
1314   }
1315 #endif
1316
1317   /* We are committed to this, so update the handler chain.  */
1318
1319   emit_move_insn (dhc, force_operand (XEXP (arg, 0), NULL_RTX));
1320 }
1321
1322 /* Start an exception handling region for the given cleanup action.
1323    All instructions emitted after this point are considered to be part
1324    of the region until expand_eh_region_end is invoked.  CLEANUP is
1325    the cleanup action to perform.  The return value is true if the
1326    exception region was optimized away.  If that case,
1327    expand_eh_region_end does not need to be called for this cleanup,
1328    nor should it be.
1329
1330    This routine notices one particular common case in C++ code
1331    generation, and optimizes it so as to not need the exception
1332    region.  It works by creating a dynamic cleanup action, instead of
1333    a using an exception region.  */
1334
1335 int
1336 expand_eh_region_start_tree (decl, cleanup)
1337      tree decl;
1338      tree cleanup;
1339 {
1340   /* This is the old code.  */
1341   if (! doing_eh (0))
1342     return 0;
1343
1344   /* The optimization only applies to actions protected with
1345      terminate, and only applies if we are using the setjmp/longjmp
1346      codegen method.  */
1347   if (exceptions_via_longjmp
1348       && protect_cleanup_actions_with_terminate)
1349     {
1350       tree func, arg;
1351       tree args;
1352
1353       /* Ignore any UNSAVE_EXPR.  */
1354       if (TREE_CODE (cleanup) == UNSAVE_EXPR)
1355         cleanup = TREE_OPERAND (cleanup, 0);
1356       
1357       /* Further, it only applies if the action is a call, if there
1358          are 2 arguments, and if the second argument is 2.  */
1359
1360       if (TREE_CODE (cleanup) == CALL_EXPR
1361           && (args = TREE_OPERAND (cleanup, 1))
1362           && (func = TREE_OPERAND (cleanup, 0))
1363           && (arg = TREE_VALUE (args))
1364           && (args = TREE_CHAIN (args))
1365
1366           /* is the second argument 2?  */
1367           && TREE_CODE (TREE_VALUE (args)) == INTEGER_CST
1368           && TREE_INT_CST_LOW (TREE_VALUE (args)) == 2
1369           && TREE_INT_CST_HIGH (TREE_VALUE (args)) == 0
1370
1371           /* Make sure there are no other arguments.  */
1372           && TREE_CHAIN (args) == NULL_TREE)
1373         {
1374           /* Arrange for returns and gotos to pop the entry we make on the
1375              dynamic cleanup stack.  */
1376           expand_dcc_cleanup (decl);
1377           start_dynamic_cleanup (func, arg);
1378           return 1;
1379         }
1380     }
1381
1382   expand_eh_region_start_for_decl (decl);
1383   ehstack.top->entry->finalization = cleanup;
1384
1385   return 0;
1386 }
1387
1388 /* Just like expand_eh_region_start, except if a cleanup action is
1389    entered on the cleanup chain, the TREE_PURPOSE of the element put
1390    on the chain is DECL.  DECL should be the associated VAR_DECL, if
1391    any, otherwise it should be NULL_TREE.  */
1392
1393 void
1394 expand_eh_region_start_for_decl (decl)
1395      tree decl;
1396 {
1397   rtx note;
1398
1399   /* This is the old code.  */
1400   if (! doing_eh (0))
1401     return;
1402
1403   /* We need a new block to record the start and end of the
1404      dynamic handler chain.  We also want to prevent jumping into
1405      a try block.  */
1406   expand_start_bindings (0);
1407
1408   /* But we don't need or want a new temporary level.  */
1409   pop_temp_slots ();
1410
1411   /* Mark this block as created by expand_eh_region_start.  This
1412      is so that we can pop the block with expand_end_bindings
1413      automatically.  */
1414   mark_block_as_eh_region ();
1415
1416   if (exceptions_via_longjmp)
1417     {
1418       /* Arrange for returns and gotos to pop the entry we make on the
1419          dynamic handler stack.  */
1420       expand_dhc_cleanup (decl);
1421     }
1422
1423   push_eh_entry (&ehstack);
1424   note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_BEG);
1425   NOTE_BLOCK_NUMBER (note)
1426     = CODE_LABEL_NUMBER (ehstack.top->entry->exception_handler_label);
1427   if (exceptions_via_longjmp)
1428     start_dynamic_handler ();
1429 }
1430
1431 /* Start an exception handling region.  All instructions emitted after
1432    this point are considered to be part of the region until
1433    expand_eh_region_end is invoked.  */
1434
1435 void
1436 expand_eh_region_start ()
1437 {
1438   expand_eh_region_start_for_decl (NULL_TREE);
1439 }
1440
1441 /* End an exception handling region.  The information about the region
1442    is found on the top of ehstack.
1443
1444    HANDLER is either the cleanup for the exception region, or if we're
1445    marking the end of a try block, HANDLER is integer_zero_node.
1446
1447    HANDLER will be transformed to rtl when expand_leftover_cleanups
1448    is invoked.  */
1449
1450 void
1451 expand_eh_region_end (handler)
1452      tree handler;
1453 {
1454   struct eh_entry *entry;
1455   rtx note;
1456   int ret, r;
1457
1458   if (! doing_eh (0))
1459     return;
1460
1461   entry = pop_eh_entry (&ehstack);
1462
1463   note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END);
1464   ret = NOTE_BLOCK_NUMBER (note)
1465     = CODE_LABEL_NUMBER (entry->exception_handler_label);
1466   if (exceptions_via_longjmp == 0 && ! flag_new_exceptions
1467       /* We share outer_context between regions; only emit it once.  */
1468       && INSN_UID (entry->outer_context) == 0)
1469     {
1470       rtx label;
1471
1472       label = gen_label_rtx ();
1473       emit_jump (label);
1474
1475       /* Emit a label marking the end of this exception region that
1476          is used for rethrowing into the outer context.  */
1477       emit_label (entry->outer_context);
1478       expand_internal_throw ();
1479
1480       emit_label (label);
1481     }
1482
1483   entry->finalization = handler;
1484
1485   /* create region entry in final exception table */
1486   r = new_eh_region_entry (NOTE_BLOCK_NUMBER (note), entry->rethrow_label);
1487
1488   enqueue_eh_entry (&ehqueue, entry);
1489
1490   /* If we have already started ending the bindings, don't recurse.  */
1491   if (is_eh_region ())
1492     {
1493       /* Because we don't need or want a new temporary level and
1494          because we didn't create one in expand_eh_region_start,
1495          create a fake one now to avoid removing one in
1496          expand_end_bindings.  */
1497       push_temp_slots ();
1498
1499       mark_block_as_not_eh_region ();
1500
1501       expand_end_bindings (NULL_TREE, 0, 0);
1502     }
1503 }
1504
1505 /* End the EH region for a goto fixup.  We only need them in the region-based
1506    EH scheme.  */
1507
1508 void
1509 expand_fixup_region_start ()
1510 {
1511   if (! doing_eh (0) || exceptions_via_longjmp)
1512     return;
1513
1514   expand_eh_region_start ();
1515 }
1516
1517 /* End the EH region for a goto fixup.  CLEANUP is the cleanup we just
1518    expanded; to avoid running it twice if it throws, we look through the
1519    ehqueue for a matching region and rethrow from its outer_context.  */
1520
1521 void
1522 expand_fixup_region_end (cleanup)
1523      tree cleanup;
1524 {
1525   struct eh_node *node;
1526   int dont_issue;
1527
1528   if (! doing_eh (0) || exceptions_via_longjmp)
1529     return;
1530
1531   for (node = ehstack.top; node && node->entry->finalization != cleanup; )
1532     node = node->chain;
1533   if (node == 0)
1534     for (node = ehqueue.head; node && node->entry->finalization != cleanup; )
1535       node = node->chain;
1536   if (node == 0)
1537     abort ();
1538
1539   /* If the outer context label has not been issued yet, we don't want
1540      to issue it as a part of this region, unless this is the
1541      correct region for the outer context. If we did, then the label for
1542      the outer context will be WITHIN the begin/end labels, 
1543      and we could get an infinte loop when it tried to rethrow, or just
1544      generally incorrect execution following a throw. */
1545
1546   dont_issue = ((INSN_UID (node->entry->outer_context) == 0) 
1547             && (ehstack.top->entry != node->entry));
1548
1549   ehstack.top->entry->outer_context = node->entry->outer_context;
1550
1551   /* Since we are rethrowing to the OUTER region, we know we don't need
1552      a jump around sequence for this region, so we'll pretend the outer 
1553      context label has been issued by setting INSN_UID to 1, then clearing
1554      it again afterwards. */
1555
1556   if (dont_issue)
1557     INSN_UID (node->entry->outer_context) = 1;
1558
1559   /* Just rethrow.  size_zero_node is just a NOP.  */
1560   expand_eh_region_end (size_zero_node);
1561
1562   if (dont_issue)
1563     INSN_UID (node->entry->outer_context) = 0;
1564 }
1565
1566 /* If we are using the setjmp/longjmp EH codegen method, we emit a
1567    call to __sjthrow.
1568
1569    Otherwise, we emit a call to __throw and note that we threw
1570    something, so we know we need to generate the necessary code for
1571    __throw.
1572
1573    Before invoking throw, the __eh_pc variable must have been set up
1574    to contain the PC being thrown from. This address is used by
1575    __throw to determine which exception region (if any) is
1576    responsible for handling the exception.  */
1577
1578 void
1579 emit_throw ()
1580 {
1581   if (exceptions_via_longjmp)
1582     {
1583       emit_library_call (sjthrow_libfunc, 0, VOIDmode, 0);
1584     }
1585   else
1586     {
1587 #ifdef JUMP_TO_THROW
1588       emit_indirect_jump (throw_libfunc);
1589 #else
1590       emit_library_call (throw_libfunc, 0, VOIDmode, 0);
1591 #endif
1592     }
1593   emit_barrier ();
1594 }
1595
1596 /* Throw the current exception.  If appropriate, this is done by jumping
1597    to the next handler.  */
1598
1599 void
1600 expand_internal_throw ()
1601 {
1602   emit_throw ();
1603 }
1604
1605 /* Called from expand_exception_blocks and expand_end_catch_block to
1606    emit any pending handlers/cleanups queued from expand_eh_region_end.  */
1607
1608 void
1609 expand_leftover_cleanups ()
1610 {
1611   struct eh_entry *entry;
1612
1613   while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
1614     {
1615       rtx prev;
1616
1617       /* A leftover try block. Shouldn't be one here.  */
1618       if (entry->finalization == integer_zero_node)
1619         abort ();
1620
1621       /* Output the label for the start of the exception handler.  */
1622
1623       receive_exception_label (entry->exception_handler_label);
1624
1625       /* register a handler for this cleanup region */
1626       add_new_handler (
1627         find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)), 
1628         get_new_handler (entry->exception_handler_label, NULL));
1629
1630       /* And now generate the insns for the handler.  */
1631       expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
1632
1633       prev = get_last_insn ();
1634       if (prev == NULL || GET_CODE (prev) != BARRIER)
1635         /* Emit code to throw to the outer context if we fall off
1636            the end of the handler.  */
1637         expand_rethrow (entry->outer_context);
1638
1639       do_pending_stack_adjust ();
1640       free (entry);
1641     }
1642 }
1643
1644 /* Called at the start of a block of try statements.  */
1645 void
1646 expand_start_try_stmts ()
1647 {
1648   if (! doing_eh (1))
1649     return;
1650
1651   expand_eh_region_start ();
1652 }
1653
1654 /* Called to begin a catch clause. The parameter is the object which
1655    will be passed to the runtime type check routine. */
1656 void 
1657 start_catch_handler (rtime)
1658      tree rtime;
1659 {
1660   rtx handler_label;
1661   int insn_region_num;
1662   int eh_region_entry;
1663
1664   if (! doing_eh (1))
1665     return;
1666
1667   handler_label = catchstack.top->entry->exception_handler_label;
1668   insn_region_num = CODE_LABEL_NUMBER (handler_label);
1669   eh_region_entry = find_func_region (insn_region_num);
1670
1671   /* If we've already issued this label, pick a new one */
1672   if (catchstack.top->entry->label_used)
1673     handler_label = gen_exception_label ();
1674   else
1675     catchstack.top->entry->label_used = 1;
1676
1677   receive_exception_label (handler_label);
1678
1679   add_new_handler (eh_region_entry, get_new_handler (handler_label, rtime));
1680
1681   if (flag_new_exceptions && ! exceptions_via_longjmp)
1682     return;
1683
1684   /* Under the old mechanism, as well as setjmp/longjmp, we need to
1685      issue code to compare 'rtime' to the value in eh_info, via the
1686      matching function in eh_info. If its is false, we branch around
1687      the handler we are about to issue. */
1688
1689   if (rtime != NULL_TREE && rtime != CATCH_ALL_TYPE)
1690     {
1691       rtx call_rtx, rtime_address;
1692
1693       if (catchstack.top->entry->false_label != NULL_RTX)
1694         fatal ("Compiler Bug: Never issued previous false_label");
1695       catchstack.top->entry->false_label = gen_exception_label ();
1696
1697       rtime_address = expand_expr (rtime, NULL_RTX, Pmode, EXPAND_INITIALIZER);
1698 #ifdef POINTERS_EXTEND_UNSIGNED
1699       rtime_address = convert_memory_address (Pmode, rtime_address);
1700 #endif
1701       rtime_address = force_reg (Pmode, rtime_address);
1702
1703       /* Now issue the call, and branch around handler if needed */
1704       call_rtx = emit_library_call_value (eh_rtime_match_libfunc, NULL_RTX, 
1705                                           0, SImode, 1, rtime_address, Pmode);
1706
1707       /* Did the function return true? */
1708       emit_cmp_and_jump_insns (call_rtx, const0_rtx, EQ, NULL_RTX,
1709                                GET_MODE (call_rtx), 0, 0,
1710                                catchstack.top->entry->false_label);
1711     }
1712 }
1713
1714 /* Called to end a catch clause. If we aren't using the new exception
1715    model tabel mechanism, we need to issue the branch-around label
1716    for the end of the catch block. */
1717
1718 void 
1719 end_catch_handler ()
1720 {
1721   if (! doing_eh (1))
1722     return;
1723
1724   if (flag_new_exceptions && ! exceptions_via_longjmp) 
1725     {
1726       emit_barrier ();
1727       return;
1728     }
1729   
1730   /* A NULL label implies the catch clause was a catch all or cleanup */
1731   if (catchstack.top->entry->false_label == NULL_RTX)
1732     return;
1733
1734   emit_label (catchstack.top->entry->false_label);
1735   catchstack.top->entry->false_label = NULL_RTX;
1736 }
1737
1738 /* Generate RTL for the start of a group of catch clauses. 
1739
1740    It is responsible for starting a new instruction sequence for the
1741    instructions in the catch block, and expanding the handlers for the
1742    internally-generated exception regions nested within the try block
1743    corresponding to this catch block.  */
1744
1745 void
1746 expand_start_all_catch ()
1747 {
1748   struct eh_entry *entry;
1749   tree label;
1750   rtx outer_context;
1751
1752   if (! doing_eh (1))
1753     return;
1754
1755   outer_context = ehstack.top->entry->outer_context;
1756
1757   /* End the try block.  */
1758   expand_eh_region_end (integer_zero_node);
1759
1760   emit_line_note (input_filename, lineno);
1761   label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
1762
1763   /* The label for the exception handling block that we will save.
1764      This is Lresume in the documentation.  */
1765   expand_label (label);
1766   
1767   /* Push the label that points to where normal flow is resumed onto
1768      the top of the label stack.  */
1769   push_label_entry (&caught_return_label_stack, NULL_RTX, label);
1770
1771   /* Start a new sequence for all the catch blocks.  We will add this
1772      to the global sequence catch_clauses when we have completed all
1773      the handlers in this handler-seq.  */
1774   start_sequence ();
1775
1776   entry = dequeue_eh_entry (&ehqueue);
1777   for ( ; entry->finalization != integer_zero_node;
1778                                  entry = dequeue_eh_entry (&ehqueue))
1779     {
1780       rtx prev;
1781
1782       /* Emit the label for the cleanup handler for this region, and
1783          expand the code for the handler. 
1784
1785          Note that a catch region is handled as a side-effect here;
1786          for a try block, entry->finalization will contain
1787          integer_zero_node, so no code will be generated in the
1788          expand_expr call below. But, the label for the handler will
1789          still be emitted, so any code emitted after this point will
1790          end up being the handler.  */
1791       
1792       receive_exception_label (entry->exception_handler_label);
1793
1794       /* register a handler for this cleanup region */
1795       add_new_handler (
1796         find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)), 
1797         get_new_handler (entry->exception_handler_label, NULL));
1798
1799       /* And now generate the insns for the cleanup handler.  */
1800       expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
1801
1802       prev = get_last_insn ();
1803       if (prev == NULL || GET_CODE (prev) != BARRIER)
1804         /* Code to throw out to outer context when we fall off end
1805            of the handler. We can't do this here for catch blocks,
1806            so it's done in expand_end_all_catch instead.  */
1807         expand_rethrow (entry->outer_context);
1808
1809       do_pending_stack_adjust ();
1810       free (entry);
1811     }
1812
1813   /* At this point, all the cleanups are done, and the ehqueue now has
1814      the current exception region at its head. We dequeue it, and put it
1815      on the catch stack. */
1816
1817     push_entry (&catchstack, entry);
1818
1819   /* If we are not doing setjmp/longjmp EH, because we are reordered
1820      out of line, we arrange to rethrow in the outer context.  We need to
1821      do this because we are not physically within the region, if any, that
1822      logically contains this catch block.  */
1823   if (! exceptions_via_longjmp)
1824     {
1825       expand_eh_region_start ();
1826       ehstack.top->entry->outer_context = outer_context;
1827     }
1828
1829 }
1830
1831 /* Finish up the catch block.  At this point all the insns for the
1832    catch clauses have already been generated, so we only have to add
1833    them to the catch_clauses list. We also want to make sure that if
1834    we fall off the end of the catch clauses that we rethrow to the
1835    outer EH region.  */
1836
1837 void
1838 expand_end_all_catch ()
1839 {
1840   rtx new_catch_clause;
1841   struct eh_entry *entry;
1842
1843   if (! doing_eh (1))
1844     return;
1845
1846   /* Dequeue the current catch clause region. */
1847   entry = pop_eh_entry (&catchstack);
1848   free (entry);
1849
1850   if (! exceptions_via_longjmp)
1851     {
1852       rtx outer_context = ehstack.top->entry->outer_context;
1853
1854       /* Finish the rethrow region.  size_zero_node is just a NOP.  */
1855       expand_eh_region_end (size_zero_node);
1856       /* New exceptions handling models will never have a fall through
1857          of a catch clause */
1858       if (!flag_new_exceptions)
1859         expand_rethrow (outer_context);
1860     }
1861   else 
1862     expand_rethrow (NULL_RTX);
1863
1864   /* Code to throw out to outer context, if we fall off end of catch
1865      handlers.  This is rethrow (Lresume, same id, same obj) in the
1866      documentation. We use Lresume because we know that it will throw
1867      to the correct context.
1868
1869      In other words, if the catch handler doesn't exit or return, we
1870      do a "throw" (using the address of Lresume as the point being
1871      thrown from) so that the outer EH region can then try to process
1872      the exception.  */
1873
1874   /* Now we have the complete catch sequence.  */
1875   new_catch_clause = get_insns ();
1876   end_sequence ();
1877   
1878   /* This level of catch blocks is done, so set up the successful
1879      catch jump label for the next layer of catch blocks.  */
1880   pop_label_entry (&caught_return_label_stack);
1881   pop_label_entry (&outer_context_label_stack);
1882
1883   /* Add the new sequence of catches to the main one for this function.  */
1884   push_to_sequence (catch_clauses);
1885   emit_insns (new_catch_clause);
1886   catch_clauses = get_insns ();
1887   end_sequence ();
1888   
1889   /* Here we fall through into the continuation code.  */
1890 }
1891
1892 /* Rethrow from the outer context LABEL.  */
1893
1894 static void
1895 expand_rethrow (label)
1896      rtx label;
1897 {
1898   if (exceptions_via_longjmp)
1899     emit_throw ();
1900   else
1901     if (flag_new_exceptions)
1902       {
1903         rtx insn, val;
1904         if (label == NULL_RTX)
1905           label = last_rethrow_symbol;
1906         emit_library_call (rethrow_libfunc, 0, VOIDmode, 1, label, Pmode);
1907         SYMBOL_REF_USED (label) = 1;
1908
1909         /* Search backwards for the actual call insn.  */
1910         insn = get_last_insn ();
1911         while (GET_CODE (insn) != CALL_INSN)
1912           insn = PREV_INSN (insn);
1913         delete_insns_since (insn);
1914         
1915         /* Mark the label/symbol on the call. */
1916         val = GEN_INT (eh_region_from_symbol (label));
1917         REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_RETHROW, val,
1918                                               REG_NOTES (insn));
1919         emit_barrier ();
1920       }
1921     else
1922       emit_jump (label);
1923 }
1924
1925 /* End all the pending exception regions on protect_list. The handlers
1926    will be emitted when expand_leftover_cleanups is invoked.  */
1927
1928 void
1929 end_protect_partials ()
1930 {
1931   while (protect_list)
1932     {
1933       expand_eh_region_end (TREE_VALUE (protect_list));
1934       protect_list = TREE_CHAIN (protect_list);
1935     }
1936 }
1937
1938 /* Arrange for __terminate to be called if there is an unhandled throw
1939    from within E.  */
1940
1941 tree
1942 protect_with_terminate (e)
1943      tree e;
1944 {
1945   /* We only need to do this when using setjmp/longjmp EH and the
1946      language requires it, as otherwise we protect all of the handlers
1947      at once, if we need to.  */
1948   if (exceptions_via_longjmp && protect_cleanup_actions_with_terminate)
1949     {
1950       tree handler, result;
1951
1952       /* All cleanups must be on the function_obstack.  */
1953       push_obstacks_nochange ();
1954       resume_temporary_allocation ();
1955
1956       handler = make_node (RTL_EXPR);
1957       TREE_TYPE (handler) = void_type_node;
1958       RTL_EXPR_RTL (handler) = const0_rtx;
1959       TREE_SIDE_EFFECTS (handler) = 1;
1960       start_sequence_for_rtl_expr (handler);
1961
1962       emit_library_call (terminate_libfunc, 0, VOIDmode, 0);
1963       emit_barrier ();
1964
1965       RTL_EXPR_SEQUENCE (handler) = get_insns ();
1966       end_sequence ();
1967         
1968       result = build (TRY_CATCH_EXPR, TREE_TYPE (e), e, handler);
1969       TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (e);
1970       TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
1971       TREE_READONLY (result) = TREE_READONLY (e);
1972
1973       pop_obstacks ();
1974
1975       e = result;
1976     }
1977
1978   return e;
1979 }
1980 \f
1981 /* The exception table that we build that is used for looking up and
1982    dispatching exceptions, the current number of entries, and its
1983    maximum size before we have to extend it. 
1984
1985    The number in eh_table is the code label number of the exception
1986    handler for the region. This is added by add_eh_table_entry and
1987    used by output_exception_table_entry.  */
1988
1989 static int *eh_table = NULL;
1990 static int eh_table_size = 0;
1991 static int eh_table_max_size = 0;
1992
1993 /* Note the need for an exception table entry for region N.  If we
1994    don't need to output an explicit exception table, avoid all of the
1995    extra work.
1996
1997    Called from final_scan_insn when a NOTE_INSN_EH_REGION_BEG is seen.
1998    (Or NOTE_INSN_EH_REGION_END sometimes)
1999    N is the NOTE_BLOCK_NUMBER of the note, which comes from the code
2000    label number of the exception handler for the region.  */
2001
2002 void
2003 add_eh_table_entry (n)
2004      int n;
2005 {
2006 #ifndef OMIT_EH_TABLE
2007   if (eh_table_size >= eh_table_max_size)
2008     {
2009       if (eh_table)
2010         {
2011           eh_table_max_size += eh_table_max_size>>1;
2012
2013           if (eh_table_max_size < 0)
2014             abort ();
2015
2016           eh_table = (int *) xrealloc (eh_table,
2017                                        eh_table_max_size * sizeof (int));
2018         }
2019       else
2020         {
2021           eh_table_max_size = 252;
2022           eh_table = (int *) xmalloc (eh_table_max_size * sizeof (int));
2023         }
2024     }
2025   eh_table[eh_table_size++] = n;
2026 #endif
2027 }
2028
2029 /* Return a non-zero value if we need to output an exception table.
2030
2031    On some platforms, we don't have to output a table explicitly.
2032    This routine doesn't mean we don't have one.  */
2033
2034 int
2035 exception_table_p ()
2036 {
2037   if (eh_table)
2038     return 1;
2039
2040   return 0;
2041 }
2042
2043 /* Output the entry of the exception table corresponding to the
2044    exception region numbered N to file FILE. 
2045
2046    N is the code label number corresponding to the handler of the
2047    region.  */
2048
2049 static void
2050 output_exception_table_entry (file, n)
2051      FILE *file;
2052      int n;
2053 {
2054   char buf[256];
2055   rtx sym;
2056   struct handler_info *handler = get_first_handler (n);
2057   int index = find_func_region (n);
2058   rtx rethrow;
2059   
2060  /* form and emit the rethrow label, if needed  */
2061   rethrow = function_eh_regions[index].rethrow_label;
2062   if (rethrow != NULL_RTX && !flag_new_exceptions)
2063       rethrow = NULL_RTX;
2064   if (rethrow != NULL_RTX && handler == NULL)
2065     if (! SYMBOL_REF_USED (rethrow))
2066       rethrow = NULL_RTX;
2067
2068
2069   for ( ; handler != NULL || rethrow != NULL_RTX; handler = handler->next)
2070     {
2071       /* rethrow label should indicate the LAST entry for a region */
2072       if (rethrow != NULL_RTX && (handler == NULL || handler->next == NULL))
2073         {
2074           ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", n);
2075           assemble_label(buf);
2076           rethrow = NULL_RTX;
2077         }
2078
2079       ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
2080       sym = gen_rtx_SYMBOL_REF (Pmode, buf);
2081       assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
2082
2083       ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
2084       sym = gen_rtx_SYMBOL_REF (Pmode, buf);
2085       assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
2086       
2087       if (handler == NULL)
2088         assemble_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1);
2089       else
2090         {
2091           ASM_GENERATE_INTERNAL_LABEL (buf, "L", handler->handler_number);
2092           sym = gen_rtx_SYMBOL_REF (Pmode, buf);
2093           assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
2094         }
2095
2096       if (flag_new_exceptions)
2097         {
2098           if (handler == NULL || handler->type_info == NULL)
2099             assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
2100           else
2101             if (handler->type_info == CATCH_ALL_TYPE)
2102               assemble_integer (GEN_INT (CATCH_ALL_TYPE), 
2103                                              POINTER_SIZE / BITS_PER_UNIT, 1);
2104             else
2105               output_constant ((tree)(handler->type_info), 
2106                                                 POINTER_SIZE / BITS_PER_UNIT);
2107         }
2108       putc ('\n', file);                /* blank line */
2109       /* We only output the first label under the old scheme */
2110       if (! flag_new_exceptions || handler == NULL)
2111         break;
2112     }
2113 }
2114
2115 /* Output the exception table if we have and need one.  */
2116
2117 static short language_code = 0;
2118 static short version_code = 0; 
2119
2120 /* This routine will set the language code for exceptions. */
2121 void
2122 set_exception_lang_code (code)
2123      int code;
2124 {
2125   language_code = code;
2126 }
2127
2128 /* This routine will set the language version code for exceptions. */
2129 void
2130 set_exception_version_code (code)
2131      int code;
2132 {
2133   version_code = code;
2134 }
2135
2136
2137 void
2138 output_exception_table ()
2139 {
2140   int i;
2141   char buf[256];
2142   extern FILE *asm_out_file;
2143
2144   if (! doing_eh (0) || ! eh_table)
2145     return;
2146
2147   exception_section ();
2148
2149   /* Beginning marker for table.  */
2150   assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
2151   assemble_label ("__EXCEPTION_TABLE__");
2152
2153   if (flag_new_exceptions)
2154     {
2155       assemble_integer (GEN_INT (NEW_EH_RUNTIME), 
2156                                         POINTER_SIZE / BITS_PER_UNIT, 1);
2157       assemble_integer (GEN_INT (language_code), 2 , 1); 
2158       assemble_integer (GEN_INT (version_code), 2 , 1);
2159
2160       /* Add enough padding to make sure table aligns on a pointer boundry. */
2161       i = GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT - 4;
2162       for ( ; i < 0; i = i + GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT)
2163         ;
2164       if (i != 0)
2165         assemble_integer (const0_rtx, i , 1);
2166
2167       /* Generate the label for offset calculations on rethrows */
2168       ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", 0);
2169       assemble_label(buf);
2170     }
2171
2172   for (i = 0; i < eh_table_size; ++i)
2173     output_exception_table_entry (asm_out_file, eh_table[i]);
2174
2175   free (eh_table);
2176   clear_function_eh_region ();
2177
2178   /* Ending marker for table.  */
2179   /* Generate the label for end of table. */
2180   ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", CODE_LABEL_NUMBER (final_rethrow));
2181   assemble_label(buf);
2182   assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
2183
2184   /* for binary compatability, the old __throw checked the second
2185      position for a -1, so we should output at least 2 -1's */
2186   if (! flag_new_exceptions)
2187     assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
2188
2189   putc ('\n', asm_out_file);            /* blank line */
2190 }
2191 \f
2192 /* Emit code to get EH context.
2193    
2194    We have to scan thru the code to find possible EH context registers.
2195    Inlined functions may use it too, and thus we'll have to be able
2196    to change them too.
2197
2198    This is done only if using exceptions_via_longjmp. */
2199
2200 void
2201 emit_eh_context ()
2202 {
2203   rtx insn;
2204   rtx ehc = 0;
2205
2206   if (! doing_eh (0))
2207     return;
2208
2209   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
2210     if (GET_CODE (insn) == INSN
2211         && GET_CODE (PATTERN (insn)) == USE)
2212       {
2213         rtx reg = find_reg_note (insn, REG_EH_CONTEXT, 0);
2214         if (reg)
2215           {
2216             rtx insns;
2217             
2218             start_sequence ();
2219
2220             /* If this is the first use insn, emit the call here.  This
2221                will always be at the top of our function, because if
2222                expand_inline_function notices a REG_EH_CONTEXT note, it
2223                adds a use insn to this function as well.  */
2224             if (ehc == 0)
2225               ehc = call_get_eh_context ();
2226
2227             emit_move_insn (XEXP (reg, 0), ehc);
2228             insns = get_insns ();
2229             end_sequence ();
2230
2231             emit_insns_before (insns, insn);
2232
2233             /* At -O0, we must make the context register stay alive so
2234                that the stupid.c register allocator doesn't get confused. */
2235             if (obey_regdecls != 0)
2236               {
2237                 insns = gen_rtx_USE (GET_MODE (XEXP (reg,0)), XEXP (reg,0));
2238                 emit_insn_before (insns, get_last_insn ());
2239               }
2240           }
2241       }
2242 }
2243
2244 /* Scan the current insns and build a list of handler labels. The
2245    resulting list is placed in the global variable exception_handler_labels.
2246
2247    It is called after the last exception handling region is added to
2248    the current function (when the rtl is almost all built for the
2249    current function) and before the jump optimization pass.  */
2250
2251 void
2252 find_exception_handler_labels ()
2253 {
2254   rtx insn;
2255
2256   exception_handler_labels = NULL_RTX;
2257
2258   /* If we aren't doing exception handling, there isn't much to check.  */
2259   if (! doing_eh (0))
2260     return;
2261
2262   /* For each start of a region, add its label to the list.  */
2263
2264   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
2265     {
2266       struct handler_info* ptr;
2267       if (GET_CODE (insn) == NOTE
2268           && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
2269         {
2270           ptr = get_first_handler (NOTE_BLOCK_NUMBER (insn));
2271           for ( ; ptr; ptr = ptr->next) 
2272             {
2273               /* make sure label isn't in the list already */
2274               rtx x;
2275               for (x = exception_handler_labels; x; x = XEXP (x, 1))
2276                 if (XEXP (x, 0) == ptr->handler_label)
2277                   break;
2278               if (! x)
2279                 exception_handler_labels = gen_rtx_EXPR_LIST (VOIDmode,
2280                                ptr->handler_label, exception_handler_labels);
2281             }
2282         }
2283     }
2284 }
2285
2286 /* Return a value of 1 if the parameter label number is an exception handler
2287    label. Return 0 otherwise. */
2288
2289 int
2290 is_exception_handler_label (lab)
2291      int lab;
2292 {
2293   rtx x;
2294   for (x = exception_handler_labels ; x ; x = XEXP (x, 1))
2295     if (lab == CODE_LABEL_NUMBER (XEXP (x, 0)))
2296       return 1;
2297   return 0;
2298 }
2299
2300 /* Perform sanity checking on the exception_handler_labels list.
2301
2302    Can be called after find_exception_handler_labels is called to
2303    build the list of exception handlers for the current function and
2304    before we finish processing the current function.  */
2305
2306 void
2307 check_exception_handler_labels ()
2308 {
2309   rtx insn, insn2;
2310
2311   /* If we aren't doing exception handling, there isn't much to check.  */
2312   if (! doing_eh (0))
2313     return;
2314
2315   /* Make sure there is no more than 1 copy of a label */
2316   for (insn = exception_handler_labels; insn; insn = XEXP (insn, 1))
2317     {
2318       int count = 0;
2319       for (insn2 = exception_handler_labels; insn2; insn2 = XEXP (insn2, 1))
2320         if (XEXP (insn, 0) == XEXP (insn2, 0))
2321           count++;
2322       if (count != 1)
2323        warning ("Counted %d copies of EH region %d in list.\n", count, 
2324                                         CODE_LABEL_NUMBER (insn));
2325     }
2326
2327 }
2328 \f
2329 /* This group of functions initializes the exception handling data
2330    structures at the start of the compilation, initializes the data
2331    structures at the start of a function, and saves and restores the
2332    exception handling data structures for the start/end of a nested
2333    function.  */
2334
2335 /* Toplevel initialization for EH things.  */ 
2336
2337 void
2338 init_eh ()
2339 {
2340   first_rethrow_symbol = create_rethrow_ref (0);
2341   final_rethrow = gen_exception_label ();
2342   last_rethrow_symbol = create_rethrow_ref (CODE_LABEL_NUMBER (final_rethrow));
2343 }
2344
2345 /* Initialize the per-function EH information.  */
2346
2347 void
2348 init_eh_for_function ()
2349 {
2350   current_function->eh = (struct eh_status *) xmalloc (sizeof (struct eh_status));
2351
2352   ehstack.top = 0;
2353   catchstack.top = 0;
2354   ehqueue.head = ehqueue.tail = 0;
2355   catch_clauses = NULL_RTX;
2356   false_label_stack = 0;
2357   caught_return_label_stack = 0;
2358   protect_list = NULL_TREE;
2359   current_function_ehc = NULL_RTX;
2360   eh_return_context = NULL_RTX;
2361   eh_return_stack_adjust = NULL_RTX;
2362   eh_return_handler = NULL_RTX;
2363   eh_return_stub_label = NULL_RTX;
2364 }
2365 \f
2366 /* This section is for the exception handling specific optimization
2367    pass.  First are the internal routines, and then the main
2368    optimization pass.  */
2369
2370 /* Determine if the given INSN can throw an exception.  */
2371
2372 static int
2373 can_throw (insn)
2374      rtx insn;
2375 {
2376   /* Calls can always potentially throw exceptions.  */
2377   if (GET_CODE (insn) == CALL_INSN)
2378     return 1;
2379
2380   if (asynchronous_exceptions)
2381     {
2382       /* If we wanted asynchronous exceptions, then everything but NOTEs
2383          and CODE_LABELs could throw.  */
2384       if (GET_CODE (insn) != NOTE && GET_CODE (insn) != CODE_LABEL)
2385         return 1;
2386     }
2387
2388   return 0;
2389 }
2390
2391 /* Scan a exception region looking for the matching end and then
2392    remove it if possible. INSN is the start of the region, N is the
2393    region number, and DELETE_OUTER is to note if anything in this
2394    region can throw.
2395
2396    Regions are removed if they cannot possibly catch an exception.
2397    This is determined by invoking can_throw on each insn within the
2398    region; if can_throw returns true for any of the instructions, the
2399    region can catch an exception, since there is an insn within the
2400    region that is capable of throwing an exception.
2401
2402    Returns the NOTE_INSN_EH_REGION_END corresponding to this region, or
2403    calls abort if it can't find one.
2404
2405    Can abort if INSN is not a NOTE_INSN_EH_REGION_BEGIN, or if N doesn't
2406    correspond to the region number, or if DELETE_OUTER is NULL.  */
2407
2408 static rtx
2409 scan_region (insn, n, delete_outer)
2410      rtx insn;
2411      int n;
2412      int *delete_outer;
2413 {
2414   rtx start = insn;
2415
2416   /* Assume we can delete the region.  */
2417   int delete = 1;
2418
2419   int r = find_func_region (n);
2420   /* Can't delete something which is rethrown to. */
2421   if (SYMBOL_REF_USED((function_eh_regions[r].rethrow_label)))
2422     delete = 0;
2423
2424   if (insn == NULL_RTX
2425       || GET_CODE (insn) != NOTE
2426       || NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
2427       || NOTE_BLOCK_NUMBER (insn) != n
2428       || delete_outer == NULL)
2429     abort ();
2430
2431   insn = NEXT_INSN (insn);
2432
2433   /* Look for the matching end.  */
2434   while (! (GET_CODE (insn) == NOTE
2435             && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
2436     {
2437       /* If anything can throw, we can't remove the region.  */
2438       if (delete && can_throw (insn))
2439         {
2440           delete = 0;
2441         }
2442
2443       /* Watch out for and handle nested regions.  */
2444       if (GET_CODE (insn) == NOTE
2445           && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
2446         {
2447           insn = scan_region (insn, NOTE_BLOCK_NUMBER (insn), &delete);
2448         }
2449
2450       insn = NEXT_INSN (insn);
2451     }
2452
2453   /* The _BEG/_END NOTEs must match and nest.  */
2454   if (NOTE_BLOCK_NUMBER (insn) != n)
2455     abort ();
2456
2457   /* If anything in this exception region can throw, we can throw.  */
2458   if (! delete)
2459     *delete_outer = 0;
2460   else
2461     {
2462       /* Delete the start and end of the region.  */
2463       delete_insn (start);
2464       delete_insn (insn);
2465
2466 /* We no longer removed labels here, since flow will now remove any
2467    handler which cannot be called any more. */
2468    
2469 #if 0
2470       /* Only do this part if we have built the exception handler
2471          labels.  */
2472       if (exception_handler_labels)
2473         {
2474           rtx x, *prev = &exception_handler_labels;
2475
2476           /* Find it in the list of handlers.  */
2477           for (x = exception_handler_labels; x; x = XEXP (x, 1))
2478             {
2479               rtx label = XEXP (x, 0);
2480               if (CODE_LABEL_NUMBER (label) == n)
2481                 {
2482                   /* If we are the last reference to the handler,
2483                      delete it.  */
2484                   if (--LABEL_NUSES (label) == 0)
2485                     delete_insn (label);
2486
2487                   if (optimize)
2488                     {
2489                       /* Remove it from the list of exception handler
2490                          labels, if we are optimizing.  If we are not, then
2491                          leave it in the list, as we are not really going to
2492                          remove the region.  */
2493                       *prev = XEXP (x, 1);
2494                       XEXP (x, 1) = 0;
2495                       XEXP (x, 0) = 0;
2496                     }
2497
2498                   break;
2499                 }
2500               prev = &XEXP (x, 1);
2501             }
2502         }
2503 #endif
2504     }
2505   return insn;
2506 }
2507
2508 /* Perform various interesting optimizations for exception handling
2509    code.
2510
2511    We look for empty exception regions and make them go (away). The
2512    jump optimization code will remove the handler if nothing else uses
2513    it.  */
2514
2515 void
2516 exception_optimize ()
2517 {
2518   rtx insn;
2519   int n;
2520
2521   /* Remove empty regions.  */
2522   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
2523     {
2524       if (GET_CODE (insn) == NOTE
2525           && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
2526         {
2527           /* Since scan_region will return the NOTE_INSN_EH_REGION_END
2528              insn, we will indirectly skip through all the insns
2529              inbetween. We are also guaranteed that the value of insn
2530              returned will be valid, as otherwise scan_region won't
2531              return.  */
2532           insn = scan_region (insn, NOTE_BLOCK_NUMBER (insn), &n);
2533         }
2534     }
2535 }
2536 \f
2537 /* Various hooks for the DWARF 2 __throw routine.  */
2538
2539 /* Do any necessary initialization to access arbitrary stack frames.
2540    On the SPARC, this means flushing the register windows.  */
2541
2542 void
2543 expand_builtin_unwind_init ()
2544 {
2545   /* Set this so all the registers get saved in our frame; we need to be
2546      able to copy the saved values for any registers from frames we unwind. */
2547   current_function_has_nonlocal_label = 1;
2548
2549 #ifdef SETUP_FRAME_ADDRESSES
2550   SETUP_FRAME_ADDRESSES ();
2551 #endif
2552 }
2553
2554 /* Given a value extracted from the return address register or stack slot,
2555    return the actual address encoded in that value.  */
2556
2557 rtx
2558 expand_builtin_extract_return_addr (addr_tree)
2559      tree addr_tree;
2560 {
2561   rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
2562   return eh_outer_context (addr);
2563 }
2564
2565 /* Given an actual address in addr_tree, do any necessary encoding
2566    and return the value to be stored in the return address register or
2567    stack slot so the epilogue will return to that address.  */
2568
2569 rtx
2570 expand_builtin_frob_return_addr (addr_tree)
2571      tree addr_tree;
2572 {
2573   rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
2574 #ifdef RETURN_ADDR_OFFSET
2575   addr = plus_constant (addr, -RETURN_ADDR_OFFSET);
2576 #endif
2577   return addr;
2578 }
2579
2580 /* Choose three registers for communication between the main body of
2581    __throw and the epilogue (or eh stub) and the exception handler. 
2582    We must do this with hard registers because the epilogue itself
2583    will be generated after reload, at which point we may not reference
2584    pseudos at all.
2585
2586    The first passes the exception context to the handler.  For this
2587    we use the return value register for a void*.
2588
2589    The second holds the stack pointer value to be restored.  For
2590    this we use the static chain register if it exists and is different
2591    from the previous, otherwise some arbitrary call-clobbered register.
2592
2593    The third holds the address of the handler itself.  Here we use
2594    some arbitrary call-clobbered register.  */
2595
2596 static void
2597 eh_regs (pcontext, psp, pra, outgoing)
2598      rtx *pcontext, *psp, *pra;
2599      int outgoing;
2600 {
2601   rtx rcontext, rsp, rra;
2602   int i;
2603
2604 #ifdef FUNCTION_OUTGOING_VALUE
2605   if (outgoing)
2606     rcontext = FUNCTION_OUTGOING_VALUE (build_pointer_type (void_type_node),
2607                                         current_function_decl);
2608   else
2609 #endif
2610     rcontext = FUNCTION_VALUE (build_pointer_type (void_type_node),
2611                                current_function_decl);
2612
2613 #ifdef STATIC_CHAIN_REGNUM
2614   if (outgoing)
2615     rsp = static_chain_incoming_rtx;
2616   else
2617     rsp = static_chain_rtx;
2618   if (REGNO (rsp) == REGNO (rcontext))
2619 #endif /* STATIC_CHAIN_REGNUM */
2620     rsp = NULL_RTX;
2621
2622   if (rsp == NULL_RTX)
2623     {
2624       for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
2625         if (call_used_regs[i] && ! fixed_regs[i] && i != REGNO (rcontext))
2626           break;
2627       if (i == FIRST_PSEUDO_REGISTER)
2628         abort();
2629
2630       rsp = gen_rtx_REG (Pmode, i);
2631     }
2632
2633   for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
2634     if (call_used_regs[i] && ! fixed_regs[i]
2635         && i != REGNO (rcontext) && i != REGNO (rsp))
2636       break;
2637   if (i == FIRST_PSEUDO_REGISTER)
2638     abort();
2639
2640   rra = gen_rtx_REG (Pmode, i);
2641
2642   *pcontext = rcontext;
2643   *psp = rsp;
2644   *pra = rra;
2645 }
2646
2647 /* Retrieve the register which contains the pointer to the eh_context
2648    structure set the __throw. */
2649
2650 rtx 
2651 get_reg_for_handler ()
2652 {
2653   rtx reg1;
2654   reg1 = FUNCTION_VALUE (build_pointer_type (void_type_node),
2655                            current_function_decl);
2656   return reg1;
2657 }
2658
2659 /* Set up the epilogue with the magic bits we'll need to return to the
2660    exception handler.  */
2661
2662 void
2663 expand_builtin_eh_return (context, stack, handler)
2664     tree context, stack, handler;
2665 {
2666   if (eh_return_context)
2667     error("Duplicate call to __builtin_eh_return");
2668
2669   eh_return_context
2670     = copy_to_reg (expand_expr (context, NULL_RTX, VOIDmode, 0));
2671   eh_return_stack_adjust
2672     = copy_to_reg (expand_expr (stack, NULL_RTX, VOIDmode, 0));
2673   eh_return_handler
2674     = copy_to_reg (expand_expr (handler, NULL_RTX, VOIDmode, 0));
2675 }
2676
2677 void
2678 expand_eh_return ()
2679 {
2680   rtx reg1, reg2, reg3;
2681   rtx stub_start, after_stub;
2682   rtx ra, tmp;
2683
2684   if (!eh_return_context)
2685     return;
2686
2687   current_function_cannot_inline = N_("function uses __builtin_eh_return");
2688
2689   eh_regs (&reg1, &reg2, &reg3, 1);
2690 #ifdef POINTERS_EXTEND_UNSIGNED
2691   eh_return_context = convert_memory_address (Pmode, eh_return_context);
2692   eh_return_stack_adjust = 
2693       convert_memory_address (Pmode, eh_return_stack_adjust);
2694   eh_return_handler = convert_memory_address (Pmode, eh_return_handler);
2695 #endif
2696   emit_move_insn (reg1, eh_return_context);
2697   emit_move_insn (reg2, eh_return_stack_adjust);
2698   emit_move_insn (reg3, eh_return_handler);
2699
2700   /* Talk directly to the target's epilogue code when possible.  */
2701
2702 #ifdef HAVE_eh_epilogue
2703   if (HAVE_eh_epilogue)
2704     {
2705       emit_insn (gen_eh_epilogue (reg1, reg2, reg3));
2706       return;
2707     }
2708 #endif
2709
2710   /* Otherwise, use the same stub technique we had before.  */
2711
2712   eh_return_stub_label = stub_start = gen_label_rtx ();
2713   after_stub = gen_label_rtx ();
2714
2715   /* Set the return address to the stub label.  */
2716
2717   ra = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
2718                                    0, hard_frame_pointer_rtx);
2719   if (GET_CODE (ra) == REG && REGNO (ra) >= FIRST_PSEUDO_REGISTER)
2720     abort();
2721
2722   tmp = memory_address (Pmode, gen_rtx_LABEL_REF (Pmode, stub_start)); 
2723 #ifdef RETURN_ADDR_OFFSET
2724   tmp = plus_constant (tmp, -RETURN_ADDR_OFFSET);
2725 #endif
2726   tmp = force_operand (tmp, ra);
2727   if (tmp != ra)
2728     emit_move_insn (ra, tmp);
2729
2730   /* Indicate that the registers are in fact used.  */
2731   emit_insn (gen_rtx_USE (VOIDmode, reg1));
2732   emit_insn (gen_rtx_USE (VOIDmode, reg2));
2733   emit_insn (gen_rtx_USE (VOIDmode, reg3));
2734   if (GET_CODE (ra) == REG)
2735     emit_insn (gen_rtx_USE (VOIDmode, ra));
2736
2737   /* Generate the stub.  */
2738
2739   emit_jump (after_stub);
2740   emit_label (stub_start);
2741
2742   eh_regs (&reg1, &reg2, &reg3, 0);
2743   adjust_stack (reg2);
2744   emit_indirect_jump (reg3);
2745
2746   emit_label (after_stub);
2747 }
2748 \f
2749
2750 /* This contains the code required to verify whether arbitrary instructions
2751    are in the same exception region. */
2752
2753 static int *insn_eh_region = (int *)0;
2754 static int maximum_uid;
2755
2756 static void
2757 set_insn_eh_region (first, region_num)
2758      rtx *first;
2759      int region_num;
2760 {
2761   rtx insn;
2762   int rnum;
2763
2764   for (insn = *first; insn; insn = NEXT_INSN (insn))
2765     {
2766       if ((GET_CODE (insn) == NOTE) && 
2767                         (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG))
2768         {
2769           rnum = NOTE_BLOCK_NUMBER (insn);
2770           insn_eh_region[INSN_UID (insn)] =  rnum;
2771           insn = NEXT_INSN (insn);
2772           set_insn_eh_region (&insn, rnum);
2773           /* Upon return, insn points to the EH_REGION_END of nested region */
2774           continue;
2775         }
2776       insn_eh_region[INSN_UID (insn)] = region_num;
2777       if ((GET_CODE (insn) == NOTE) && 
2778             (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
2779         break;
2780     }
2781   *first = insn;
2782 }
2783
2784 /* Free the insn table, an make sure it cannot be used again. */
2785
2786 void 
2787 free_insn_eh_region () 
2788 {
2789   if (!doing_eh (0))
2790     return;
2791
2792   if (insn_eh_region)
2793     {
2794       free (insn_eh_region);
2795       insn_eh_region = (int *)0;
2796     }
2797 }
2798
2799 /* Initialize the table. max_uid must be calculated and handed into 
2800    this routine. If it is unavailable, passing a value of 0 will 
2801    cause this routine to calculate it as well. */
2802
2803 void 
2804 init_insn_eh_region (first, max_uid)
2805      rtx first;
2806      int max_uid;
2807 {
2808   rtx insn;
2809
2810   if (!doing_eh (0))
2811     return;
2812
2813   if (insn_eh_region)
2814     free_insn_eh_region();
2815
2816   if (max_uid == 0) 
2817     for (insn = first; insn; insn = NEXT_INSN (insn))
2818       if (INSN_UID (insn) > max_uid)       /* find largest UID */
2819         max_uid = INSN_UID (insn);
2820
2821   maximum_uid = max_uid;
2822   insn_eh_region = (int *) malloc ((max_uid + 1) * sizeof (int));
2823   insn = first;
2824   set_insn_eh_region (&insn, 0);
2825 }
2826
2827
2828 /* Check whether 2 instructions are within the same region. */
2829
2830 int 
2831 in_same_eh_region (insn1, insn2) 
2832      rtx insn1, insn2;
2833 {
2834   int ret, uid1, uid2;
2835
2836   /* If no exceptions, instructions are always in same region. */
2837   if (!doing_eh (0))
2838     return 1;
2839
2840   /* If the table isn't allocated, assume the worst. */
2841   if (!insn_eh_region)  
2842     return 0;
2843
2844   uid1 = INSN_UID (insn1);
2845   uid2 = INSN_UID (insn2);
2846
2847   /* if instructions have been allocated beyond the end, either
2848      the table is out of date, or this is a late addition, or
2849      something... Assume the worst. */
2850   if (uid1 > maximum_uid || uid2 > maximum_uid)
2851     return 0;
2852
2853   ret = (insn_eh_region[uid1] == insn_eh_region[uid2]);
2854   return ret;
2855 }
2856