except.c revision 52284
1194246Smarius/* Implements exception handling.
2194246Smarius   Copyright (C) 1989, 92-97, 1998 Free Software Foundation, Inc.
3194246Smarius   Contributed by Mike Stump <mrs@cygnus.com>.
4194246Smarius
5194246SmariusThis file is part of GNU CC.
6194246Smarius
7194246SmariusGNU CC is free software; you can redistribute it and/or modify
8194246Smariusit under the terms of the GNU General Public License as published by
9194246Smariusthe Free Software Foundation; either version 2, or (at your option)
10194246Smariusany later version.
11194246Smarius
12194246SmariusGNU CC is distributed in the hope that it will be useful,
13194246Smariusbut WITHOUT ANY WARRANTY; without even the implied warranty of
14194246SmariusMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15194246SmariusGNU General Public License for more details.
16194246Smarius
17194246SmariusYou should have received a copy of the GNU General Public License
18194246Smariusalong with GNU CC; see the file COPYING.  If not, write to
19194246Smariusthe Free Software Foundation, 59 Temple Place - Suite 330,
20194246SmariusBoston, MA 02111-1307, USA.  */
21194246Smarius
22194246Smarius
23194246Smarius/* An exception is an event that can be signaled from within a
24194246Smarius   function. This event can then be "caught" or "trapped" by the
25194246Smarius   callers of this function. This potentially allows program flow to
26194246Smarius   be transferred to any arbitrary code associated with a function call
27194246Smarius   several levels up the stack.
28194246Smarius
29194246Smarius   The intended use for this mechanism is for signaling "exceptional
30194246Smarius   events" in an out-of-band fashion, hence its name. The C++ language
31194246Smarius   (and many other OO-styled or functional languages) practically
32194246Smarius   requires such a mechanism, as otherwise it becomes very difficult
33194246Smarius   or even impossible to signal failure conditions in complex
34194246Smarius   situations.  The traditional C++ example is when an error occurs in
35194246Smarius   the process of constructing an object; without such a mechanism, it
36194246Smarius   is impossible to signal that the error occurs without adding global
37194246Smarius   state variables and error checks around every object construction.
38194246Smarius
39194246Smarius   The act of causing this event to occur is referred to as "throwing
40194246Smarius   an exception". (Alternate terms include "raising an exception" or
41194246Smarius   "signaling an exception".) The term "throw" is used because control
42194246Smarius   is returned to the callers of the function that is signaling the
43194246Smarius   exception, and thus there is the concept of "throwing" the
44194246Smarius   exception up the call stack.
45194246Smarius
46194246Smarius   There are two major codegen options for exception handling.  The
47194246Smarius   flag -fsjlj-exceptions can be used to select the setjmp/longjmp
48194246Smarius   approach, which is the default.  -fno-sjlj-exceptions can be used to
49194246Smarius   get the PC range table approach.  While this is a compile time
50194246Smarius   flag, an entire application must be compiled with the same codegen
51194246Smarius   option.  The first is a PC range table approach, the second is a
52194246Smarius   setjmp/longjmp based scheme.  We will first discuss the PC range
53194246Smarius   table approach, after that, we will discuss the setjmp/longjmp
54194246Smarius   based approach.
55194246Smarius
56194246Smarius   It is appropriate to speak of the "context of a throw". This
57194246Smarius   context refers to the address where the exception is thrown from,
58194246Smarius   and is used to determine which exception region will handle the
59194246Smarius   exception.
60194904Smarius
61194246Smarius   Regions of code within a function can be marked such that if it
62194246Smarius   contains the context of a throw, control will be passed to a
63194246Smarius   designated "exception handler". These areas are known as "exception
64194246Smarius   regions".  Exception regions cannot overlap, but they can be nested
65194246Smarius   to any arbitrary depth. Also, exception regions cannot cross
66194246Smarius   function boundaries.
67194246Smarius
68194246Smarius   Exception handlers can either be specified by the user (which we
69194246Smarius   will call a "user-defined handler") or generated by the compiler
70194246Smarius   (which we will designate as a "cleanup"). Cleanups are used to
71194246Smarius   perform tasks such as destruction of objects allocated on the
72194246Smarius   stack.
73194246Smarius
74194246Smarius   In the current implementation, cleanups are handled by allocating an
75194246Smarius   exception region for the area that the cleanup is designated for,
76194246Smarius   and the handler for the region performs the cleanup and then
77194246Smarius   rethrows the exception to the outer exception region. From the
78194246Smarius   standpoint of the current implementation, there is little
79207585Smarius   distinction made between a cleanup and a user-defined handler, and
80194246Smarius   the phrase "exception handler" can be used to refer to either one
81194246Smarius   equally well. (The section "Future Directions" below discusses how
82194246Smarius   this will change).
83194246Smarius
84194246Smarius   Each object file that is compiled with exception handling contains
85194246Smarius   a static array of exception handlers named __EXCEPTION_TABLE__.
86194246Smarius   Each entry contains the starting and ending addresses of the
87194246Smarius   exception region, and the address of the handler designated for
88194246Smarius   that region.
89194246Smarius
90194246Smarius   If the target does not use the DWARF 2 frame unwind information, at
91194246Smarius   program startup each object file invokes a function named
92194246Smarius   __register_exceptions with the address of its local
93194246Smarius   __EXCEPTION_TABLE__. __register_exceptions is defined in libgcc2.c, and
94194246Smarius   is responsible for recording all of the exception regions into one list
95194246Smarius   (which is kept in a static variable named exception_table_list).
96194246Smarius
97194246Smarius   On targets that support crtstuff.c, the unwind information
98194246Smarius   is stored in a section named .eh_frame and the information for the
99194246Smarius   entire shared object or program is registered with a call to
100194246Smarius   __register_frame_info.  On other targets, the information for each
101194246Smarius   translation unit is registered from the file generated by collect2.
102194246Smarius   __register_frame_info is defined in frame.c, and is responsible for
103194246Smarius   recording all of the unwind regions into one list (which is kept in a
104194246Smarius   static variable named unwind_table_list).
105194246Smarius
106194246Smarius   The function __throw is actually responsible for doing the
107194246Smarius   throw. On machines that have unwind info support, __throw is generated
108194246Smarius   by code in libgcc2.c, otherwise __throw is generated on a
109194246Smarius   per-object-file basis for each source file compiled with
110194246Smarius   -fexceptions by the C++ frontend.  Before __throw is invoked,
111194246Smarius   the current context of the throw needs to be placed in the global
112194246Smarius   variable __eh_pc.
113194246Smarius
114194246Smarius   __throw attempts to find the appropriate exception handler for the
115194246Smarius   PC value stored in __eh_pc by calling __find_first_exception_table_match
116194246Smarius   (which is defined in libgcc2.c). If __find_first_exception_table_match
117194246Smarius   finds a relevant handler, __throw transfers control directly to it.
118194246Smarius
119194246Smarius   If a handler for the context being thrown from can't be found, __throw
120194246Smarius   walks (see Walking the stack below) the stack up the dynamic call chain to
121194246Smarius   continue searching for an appropriate exception handler based upon the
122194246Smarius   caller of the function it last sought a exception handler for.  It stops
123194246Smarius   then either an exception handler is found, or when the top of the
124194246Smarius   call chain is reached.
125194246Smarius
126194246Smarius   If no handler is found, an external library function named
127194246Smarius   __terminate is called.  If a handler is found, then we restart
128194246Smarius   our search for a handler at the end of the call chain, and repeat
129194246Smarius   the search process, but instead of just walking up the call chain,
130194246Smarius   we unwind the call chain as we walk up it.
131194246Smarius
132194246Smarius   Internal implementation details:
133194246Smarius
134194246Smarius   To associate a user-defined handler with a block of statements, the
135194246Smarius   function expand_start_try_stmts is used to mark the start of the
136194246Smarius   block of statements with which the handler is to be associated
137194246Smarius   (which is known as a "try block"). All statements that appear
138194246Smarius   afterwards will be associated with the try block.
139194904Smarius
140194904Smarius   A call to expand_start_all_catch marks the end of the try block,
141194246Smarius   and also marks the start of the "catch block" (the user-defined
142194246Smarius   handler) associated with the try block.
143194246Smarius
144194246Smarius   This user-defined handler will be invoked for *every* exception
145194246Smarius   thrown with the context of the try block. It is up to the handler
146194246Smarius   to decide whether or not it wishes to handle any given exception,
147194246Smarius   as there is currently no mechanism in this implementation for doing
148194246Smarius   this. (There are plans for conditionally processing an exception
149194246Smarius   based on its "type", which will provide a language-independent
150194246Smarius   mechanism).
151194246Smarius
152194246Smarius   If the handler chooses not to process the exception (perhaps by
153194246Smarius   looking at an "exception type" or some other additional data
154194246Smarius   supplied with the exception), it can fall through to the end of the
155194246Smarius   handler. expand_end_all_catch and expand_leftover_cleanups
156194246Smarius   add additional code to the end of each handler to take care of
157194246Smarius   rethrowing to the outer exception handler.
158194246Smarius
159194246Smarius   The handler also has the option to continue with "normal flow of
160194246Smarius   code", or in other words to resume executing at the statement
161194246Smarius   immediately after the end of the exception region. The variable
162194246Smarius   caught_return_label_stack contains a stack of labels, and jumping
163194246Smarius   to the topmost entry's label via expand_goto will resume normal
164194246Smarius   flow to the statement immediately after the end of the exception
165194246Smarius   region. If the handler falls through to the end, the exception will
166194246Smarius   be rethrown to the outer exception region.
167194246Smarius
168194904Smarius   The instructions for the catch block are kept as a separate
169194246Smarius   sequence, and will be emitted at the end of the function along with
170194904Smarius   the handlers specified via expand_eh_region_end. The end of the
171194246Smarius   catch block is marked with expand_end_all_catch.
172194246Smarius
173194246Smarius   Any data associated with the exception must currently be handled by
174194246Smarius   some external mechanism maintained in the frontend.  For example,
175194246Smarius   the C++ exception mechanism passes an arbitrary value along with
176194246Smarius   the exception, and this is handled in the C++ frontend by using a
177194246Smarius   global variable to hold the value. (This will be changing in the
178194246Smarius   future.)
179210334Sattilio
180194246Smarius   The mechanism in C++ for handling data associated with the
181194246Smarius   exception is clearly not thread-safe. For a thread-based
182194246Smarius   environment, another mechanism must be used (possibly using a
183194246Smarius   per-thread allocation mechanism if the size of the area that needs
184194246Smarius   to be allocated isn't known at compile time.)
185194246Smarius
186194246Smarius   Internally-generated exception regions (cleanups) are marked by
187194246Smarius   calling expand_eh_region_start to mark the start of the region,
188194246Smarius   and expand_eh_region_end (handler) is used to both designate the
189194246Smarius   end of the region and to associate a specified handler/cleanup with
190194246Smarius   the region. The rtl code in HANDLER will be invoked whenever an
191194246Smarius   exception occurs in the region between the calls to
192194246Smarius   expand_eh_region_start and expand_eh_region_end. After HANDLER is
193194246Smarius   executed, additional code is emitted to handle rethrowing the
194194246Smarius   exception to the outer exception handler. The code for HANDLER will
195194246Smarius   be emitted at the end of the function.
196194246Smarius
197194246Smarius   TARGET_EXPRs can also be used to designate exception regions. A
198194246Smarius   TARGET_EXPR gives an unwind-protect style interface commonly used
199194246Smarius   in functional languages such as LISP. The associated expression is
200194246Smarius   evaluated, and whether or not it (or any of the functions that it
201194246Smarius   calls) throws an exception, the protect expression is always
202194246Smarius   invoked. This implementation takes care of the details of
203194246Smarius   associating an exception table entry with the expression and
204194246Smarius   generating the necessary code (it actually emits the protect
205194246Smarius   expression twice, once for normal flow and once for the exception
206223986Smarius   case). As for the other handlers, the code for the exception case
207194904Smarius   will be emitted at the end of the function.
208194904Smarius
209194904Smarius   Cleanups can also be specified by using add_partial_entry (handler)
210194904Smarius   and end_protect_partials. add_partial_entry creates the start of
211194904Smarius   a new exception region; HANDLER will be invoked if an exception is
212194904Smarius   thrown with the context of the region between the calls to
213194904Smarius   add_partial_entry and end_protect_partials. end_protect_partials is
214194904Smarius   used to mark the end of these regions. add_partial_entry can be
215194904Smarius   called as many times as needed before calling end_protect_partials.
216194904Smarius   However, end_protect_partials should only be invoked once for each
217245923Smarius   group of calls to add_partial_entry as the entries are queued
218194904Smarius   and all of the outstanding entries are processed simultaneously
219245923Smarius   when end_protect_partials is invoked. Similarly to the other
220245923Smarius   handlers, the code for HANDLER will be emitted at the end of the
221245923Smarius   function.
222245923Smarius
223194246Smarius   The generated RTL for an exception region includes
224194246Smarius   NOTE_INSN_EH_REGION_BEG and NOTE_INSN_EH_REGION_END notes that mark
225194246Smarius   the start and end of the exception region. A unique label is also
226194246Smarius   generated at the start of the exception region, which is available
227194246Smarius   by looking at the ehstack variable. The topmost entry corresponds
228194246Smarius   to the current region.
229194246Smarius
230194246Smarius   In the current implementation, an exception can only be thrown from
231194246Smarius   a function call (since the mechanism used to actually throw an
232194904Smarius   exception involves calling __throw).  If an exception region is
233194246Smarius   created but no function calls occur within that region, the region
234194246Smarius   can be safely optimized away (along with its exception handlers)
235194246Smarius   since no exceptions can ever be caught in that region.  This
236194246Smarius   optimization is performed unless -fasynchronous-exceptions is
237194246Smarius   given.  If the user wishes to throw from a signal handler, or other
238194246Smarius   asynchronous place, -fasynchronous-exceptions should be used when
239194246Smarius   compiling for maximally correct code, at the cost of additional
240194246Smarius   exception regions.  Using -fasynchronous-exceptions only produces
241194246Smarius   code that is reasonably safe in such situations, but a correct
242194246Smarius   program cannot rely upon this working.  It can be used in failsafe
243194246Smarius   code, where trying to continue on, and proceeding with potentially
244194246Smarius   incorrect results is better than halting the program.
245194246Smarius
246194246Smarius
247194246Smarius   Walking the stack:
248194246Smarius
249194246Smarius   The stack is walked by starting with a pointer to the current
250194246Smarius   frame, and finding the pointer to the callers frame.  The unwind info
251194246Smarius   tells __throw how to find it.
252194246Smarius
253194246Smarius   Unwinding the stack:
254194246Smarius
255194246Smarius   When we use the term unwinding the stack, we mean undoing the
256194246Smarius   effects of the function prologue in a controlled fashion so that we
257194246Smarius   still have the flow of control.  Otherwise, we could just return
258194246Smarius   (jump to the normal end of function epilogue).
259194246Smarius
260194246Smarius   This is done in __throw in libgcc2.c when we know that a handler exists
261194246Smarius   in a frame higher up the call stack than its immediate caller.
262194246Smarius
263194246Smarius   To unwind, we find the unwind data associated with the frame, if any.
264194246Smarius   If we don't find any, we call the library routine __terminate.  If we do
265194246Smarius   find it, we use the information to copy the saved register values from
266194246Smarius   that frame into the register save area in the frame for __throw, return
267194246Smarius   into a stub which updates the stack pointer, and jump to the handler.
268194246Smarius   The normal function epilogue for __throw handles restoring the saved
269194246Smarius   values into registers.
270194246Smarius
271194246Smarius   When unwinding, we use this method if we know it will
272194246Smarius   work (if DWARF2_UNWIND_INFO is defined).  Otherwise, we know that
273194246Smarius   an inline unwinder will have been emitted for any function that
274194246Smarius   __unwind_function cannot unwind.  The inline unwinder appears as a
275194246Smarius   normal exception handler for the entire function, for any function
276194246Smarius   that we know cannot be unwound by __unwind_function.  We inform the
277194246Smarius   compiler of whether a function can be unwound with
278194246Smarius   __unwind_function by having DOESNT_NEED_UNWINDER evaluate to true
279194246Smarius   when the unwinder isn't needed.  __unwind_function is used as an
280194246Smarius   action of last resort.  If no other method can be used for
281194246Smarius   unwinding, __unwind_function is used.  If it cannot unwind, it
282194246Smarius   should call __terminate.
283194246Smarius
284194246Smarius   By default, if the target-specific backend doesn't supply a definition
285194246Smarius   for __unwind_function and doesn't support DWARF2_UNWIND_INFO, inlined
286194246Smarius   unwinders will be used instead. The main tradeoff here is in text space
287194246Smarius   utilization.  Obviously, if inline unwinders have to be generated
288194246Smarius   repeatedly, this uses much more space than if a single routine is used.
289194246Smarius
290194246Smarius   However, it is simply not possible on some platforms to write a
291194246Smarius   generalized routine for doing stack unwinding without having some
292194246Smarius   form of additional data associated with each function.  The current
293194246Smarius   implementation can encode this data in the form of additional
294194246Smarius   machine instructions or as static data in tabular form.  The later
295194246Smarius   is called the unwind data.
296194246Smarius
297194246Smarius   The backend macro DOESNT_NEED_UNWINDER is used to conditionalize whether
298194246Smarius   or not per-function unwinders are needed. If DOESNT_NEED_UNWINDER is
299194246Smarius   defined and has a non-zero value, a per-function unwinder is not emitted
300194246Smarius   for the current function.  If the static unwind data is supported, then
301194246Smarius   a per-function unwinder is not emitted.
302194246Smarius
303194246Smarius   On some platforms it is possible that neither __unwind_function
304194246Smarius   nor inlined unwinders are available. For these platforms it is not
305194246Smarius   possible to throw through a function call, and abort will be
306194246Smarius   invoked instead of performing the throw.
307194246Smarius
308194246Smarius   The reason the unwind data may be needed is that on some platforms
309194246Smarius   the order and types of data stored on the stack can vary depending
310194246Smarius   on the type of function, its arguments and returned values, and the
311194246Smarius   compilation options used (optimization versus non-optimization,
312194246Smarius   -fomit-frame-pointer, processor variations, etc).
313194246Smarius
314194246Smarius   Unfortunately, this also means that throwing through functions that
315194246Smarius   aren't compiled with exception handling support will still not be
316194246Smarius   possible on some platforms. This problem is currently being
317194246Smarius   investigated, but no solutions have been found that do not imply
318194246Smarius   some unacceptable performance penalties.
319194246Smarius
320194246Smarius   Future directions:
321194246Smarius
322194246Smarius   Currently __throw makes no differentiation between cleanups and
323194246Smarius   user-defined exception regions. While this makes the implementation
324194246Smarius   simple, it also implies that it is impossible to determine if a
325194246Smarius   user-defined exception handler exists for a given exception without
326194246Smarius   completely unwinding the stack in the process. This is undesirable
327194246Smarius   from the standpoint of debugging, as ideally it would be possible
328194246Smarius   to trap unhandled exceptions in the debugger before the process of
329207585Smarius   unwinding has even started.
330207585Smarius
331207585Smarius   This problem can be solved by marking user-defined handlers in a
332207585Smarius   special way (probably by adding additional bits to exception_table_list).
333207585Smarius   A two-pass scheme could then be used by __throw to iterate
334207585Smarius   through the table. The first pass would search for a relevant
335207585Smarius   user-defined handler for the current context of the throw, and if
336207585Smarius   one is found, the second pass would then invoke all needed cleanups
337207585Smarius   before jumping to the user-defined handler.
338207585Smarius
339207585Smarius   Many languages (including C++ and Ada) make execution of a
340207585Smarius   user-defined handler conditional on the "type" of the exception
341207585Smarius   thrown. (The type of the exception is actually the type of the data
342207585Smarius   that is thrown with the exception.) It will thus be necessary for
343207585Smarius   __throw to be able to determine if a given user-defined
344207585Smarius   exception handler will actually be executed, given the type of
345207585Smarius   exception.
346245923Smarius
347245923Smarius   One scheme is to add additional information to exception_table_list
348245923Smarius   as to the types of exceptions accepted by each handler. __throw
349207585Smarius   can do the type comparisons and then determine if the handler is
350207585Smarius   actually going to be executed.
351207585Smarius
352245923Smarius   There is currently no significant level of debugging support
353207585Smarius   available, other than to place a breakpoint on __throw. While
354213893Smarius   this is sufficient in most cases, it would be helpful to be able to
355213893Smarius   know where a given exception was going to be thrown to before it is
356215721Smarius   actually thrown, and to be able to choose between stopping before
357194246Smarius   every exception region (including cleanups), or just user-defined
358207585Smarius   exception regions. This should be possible to do in the two-pass
359207585Smarius   scheme by adding additional labels to __throw for appropriate
360207585Smarius   breakpoints, and additional debugger commands could be added to
361207585Smarius   query various state variables to determine what actions are to be
362207585Smarius   performed next.
363207585Smarius
364207585Smarius   Another major problem that is being worked on is the issue with stack
365207585Smarius   unwinding on various platforms. Currently the only platforms that have
366207585Smarius   support for the generation of a generic unwinder are the SPARC and MIPS.
367207585Smarius   All other ports require per-function unwinders, which produce large
368207585Smarius   amounts of code bloat.
369245923Smarius
370207585Smarius   For setjmp/longjmp based exception handling, some of the details
371207585Smarius   are as above, but there are some additional details.  This section
372207585Smarius   discusses the details.
373207585Smarius
374245923Smarius   We don't use NOTE_INSN_EH_REGION_{BEG,END} pairs.  We don't
375207585Smarius   optimize EH regions yet.  We don't have to worry about machine
376213893Smarius   specific issues with unwinding the stack, as we rely upon longjmp
377213893Smarius   for all the machine specific details.  There is no variable context
378215721Smarius   of a throw, just the one implied by the dynamic handler stack
379194246Smarius   pointed to by the dynamic handler chain.  There is no exception
380207585Smarius   table, and no calls to __register_exceptions.  __sjthrow is used
381207585Smarius   instead of __throw, and it works by using the dynamic handler
382207585Smarius   chain, and longjmp.  -fasynchronous-exceptions has no effect, as
383207585Smarius   the elimination of trivial exception regions is not yet performed.
384194246Smarius
385207585Smarius   A frontend can set protect_cleanup_actions_with_terminate when all
386207585Smarius   the cleanup actions should be protected with an EH region that
387207585Smarius   calls terminate when an unhandled exception is throw.  C++ does
388207585Smarius   this, Ada does not.  */
389207585Smarius
390207585Smarius
391207585Smarius#include "config.h"
392194246Smarius#include "defaults.h"
393207585Smarius#include "eh-common.h"
394207585Smarius#include "system.h"
395207585Smarius#include "rtl.h"
396207585Smarius#include "tree.h"
397207585Smarius#include "flags.h"
398213893Smarius#include "except.h"
399213893Smarius#include "function.h"
400215721Smarius#include "insn-flags.h"
401194246Smarius#include "expr.h"
402194246Smarius#include "insn-codes.h"
403213893Smarius#include "regs.h"
404194246Smarius#include "hard-reg-set.h"
405194246Smarius#include "insn-config.h"
406194246Smarius#include "recog.h"
407194246Smarius#include "output.h"
408194246Smarius#include "toplev.h"
409194246Smarius#include "intl.h"
410194246Smarius#include "obstack.h"
411194246Smarius
412194246Smarius/* One to use setjmp/longjmp method of generating code for exception
413194246Smarius   handling.  */
414194246Smarius
415194246Smariusint exceptions_via_longjmp = 2;
416194246Smarius
417194246Smarius/* One to enable asynchronous exception support.  */
418194246Smarius
419194246Smariusint asynchronous_exceptions = 0;
420194246Smarius
421194246Smarius/* One to protect cleanup actions with a handler that calls
422194246Smarius   __terminate, zero otherwise.  */
423194246Smarius
424194246Smariusint protect_cleanup_actions_with_terminate;
425194246Smarius
426194246Smarius/* A list of labels used for exception handlers.  Created by
427194246Smarius   find_exception_handler_labels for the optimization passes.  */
428194246Smarius
429194246Smariusrtx exception_handler_labels;
430194246Smarius
431194246Smarius/* The EH context.  Nonzero if the function has already
432194246Smarius   fetched a pointer to the EH context  for exception handling.  */
433194246Smarius
434194246Smariusrtx current_function_ehc;
435194246Smarius
436194246Smarius/* A stack used for keeping track of the currently active exception
437194246Smarius   handling region.  As each exception region is started, an entry
438194246Smarius   describing the region is pushed onto this stack.  The current
439194246Smarius   region can be found by looking at the top of the stack, and as we
440194246Smarius   exit regions, the corresponding entries are popped.
441194246Smarius
442194246Smarius   Entries cannot overlap; they can be nested. So there is only one
443194246Smarius   entry at most that corresponds to the current instruction, and that
444194246Smarius   is the entry on the top of the stack.  */
445194246Smarius
446194246Smariusstatic struct eh_stack ehstack;
447194246Smarius
448194246Smarius
449194246Smarius/* This stack is used to represent what the current eh region is
450194246Smarius   for the catch blocks beings processed */
451194246Smarius
452194246Smariusstatic struct eh_stack catchstack;
453194246Smarius
454194246Smarius/* A queue used for tracking which exception regions have closed but
455194246Smarius   whose handlers have not yet been expanded. Regions are emitted in
456194246Smarius   groups in an attempt to improve paging performance.
457194246Smarius
458194246Smarius   As we exit a region, we enqueue a new entry. The entries are then
459194246Smarius   dequeued during expand_leftover_cleanups and expand_start_all_catch,
460194246Smarius
461194246Smarius   We should redo things so that we either take RTL for the handler,
462194246Smarius   or we expand the handler expressed as a tree immediately at region
463194246Smarius   end time.  */
464194246Smarius
465194246Smariusstatic struct eh_queue ehqueue;
466194246Smarius
467194904Smarius/* Insns for all of the exception handlers for the current function.
468194904Smarius   They are currently emitted by the frontend code.  */
469194246Smarius
470194246Smariusrtx catch_clauses;
471194246Smarius
472194246Smarius/* A TREE_CHAINed list of handlers for regions that are not yet
473194246Smarius   closed. The TREE_VALUE of each entry contains the handler for the
474194246Smarius   corresponding entry on the ehstack.  */
475194246Smarius
476194246Smariusstatic tree protect_list;
477194246Smarius
478194246Smarius/* Stacks to keep track of various labels.  */
479194246Smarius
480194904Smarius/* Keeps track of the label to resume to should one want to resume
481194246Smarius   normal control flow out of a handler (instead of, say, returning to
482194246Smarius   the caller of the current function or exiting the program).  */
483194246Smarius
484194246Smariusstruct label_node *caught_return_label_stack = NULL;
485194246Smarius
486194904Smarius/* Keeps track of the label used as the context of a throw to rethrow an
487194904Smarius   exception to the outer exception region.  */
488194246Smarius
489194904Smariusstruct label_node *outer_context_label_stack = NULL;
490194246Smarius
491194246Smarius/* A random data area for the front end's own use.  */
492194246Smarius
493194246Smariusstruct label_node *false_label_stack = NULL;
494194246Smarius
495194246Smarius/* Pseudos used to hold exception return data in the interim between
496194246Smarius   __builtin_eh_return and the end of the function.  */
497194246Smarius
498194246Smariusstatic rtx eh_return_context;
499194246Smariusstatic rtx eh_return_stack_adjust;
500194246Smariusstatic rtx eh_return_handler;
501194246Smarius
502194246Smarius/* Used to mark the eh return stub for flow, so that the Right Thing
503194246Smarius   happens with the values for the hardregs therin.  */
504194246Smarius
505194246Smariusrtx eh_return_stub_label;
506194246Smarius
507194246Smarius/* This is used for targets which can call rethrow with an offset instead
508194246Smarius   of an address. This is subtracted from the rethrow label we are
509194246Smarius   interested in. */
510194246Smarius
511194246Smariusstatic rtx first_rethrow_symbol = NULL_RTX;
512194246Smariusstatic rtx final_rethrow = NULL_RTX;
513194246Smariusstatic rtx last_rethrow_symbol = NULL_RTX;
514194246Smarius
515194246Smarius
516194246Smarius/* Prototypes for local functions.  */
517194246Smarius
518194246Smariusstatic void push_eh_entry	PROTO((struct eh_stack *));
519194246Smariusstatic struct eh_entry * pop_eh_entry		PROTO((struct eh_stack *));
520194246Smariusstatic void enqueue_eh_entry	PROTO((struct eh_queue *, struct eh_entry *));
521194246Smariusstatic struct eh_entry * dequeue_eh_entry	PROTO((struct eh_queue *));
522194246Smariusstatic rtx call_get_eh_context	PROTO((void));
523194246Smariusstatic void start_dynamic_cleanup		PROTO((tree, tree));
524194246Smariusstatic void start_dynamic_handler		PROTO((void));
525194246Smariusstatic void expand_rethrow	PROTO((rtx));
526194246Smariusstatic void output_exception_table_entry	PROTO((FILE *, int));
527194246Smariusstatic int can_throw		PROTO((rtx));
528194246Smariusstatic rtx scan_region		PROTO((rtx, int, int *));
529194246Smariusstatic void eh_regs		PROTO((rtx *, rtx *, rtx *, int));
530194246Smariusstatic void set_insn_eh_region	PROTO((rtx *, int));
531194246Smarius#ifdef DONT_USE_BUILTIN_SETJMP
532194246Smariusstatic void jumpif_rtx		PROTO((rtx, rtx));
533194246Smarius#endif
534194246Smarius
535194246Smariusrtx expand_builtin_return_addr	PROTO((enum built_in_function, int, rtx));
536194246Smarius
537194246Smarius/* Various support routines to manipulate the various data structures
538194246Smarius   used by the exception handling code.  */
539194246Smarius
540194246Smariusextern struct obstack permanent_obstack;
541194246Smarius
542194246Smarius/* Generate a SYMBOL_REF for rethrow to use */
543194246Smariusstatic rtx
544194246Smariuscreate_rethrow_ref (region_num)
545194246Smarius     int region_num;
546194246Smarius{
547194246Smarius  rtx def;
548194246Smarius  char *ptr;
549194246Smarius  char buf[60];
550194246Smarius
551194246Smarius  push_obstacks_nochange ();
552194246Smarius  end_temporary_allocation ();
553194246Smarius
554194246Smarius  ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", region_num);
555194246Smarius  ptr = (char *) obstack_copy0 (&permanent_obstack, buf, strlen (buf));
556194246Smarius  def = gen_rtx_SYMBOL_REF (Pmode, ptr);
557194246Smarius  SYMBOL_REF_NEED_ADJUST (def) = 1;
558194246Smarius
559194246Smarius  pop_obstacks ();
560194246Smarius  return def;
561194246Smarius}
562194246Smarius
563194246Smarius/* Push a label entry onto the given STACK.  */
564194246Smarius
565194246Smariusvoid
566194246Smariuspush_label_entry (stack, rlabel, tlabel)
567194246Smarius     struct label_node **stack;
568194246Smarius     rtx rlabel;
569194246Smarius     tree tlabel;
570194246Smarius{
571194246Smarius  struct label_node *newnode
572194246Smarius    = (struct label_node *) xmalloc (sizeof (struct label_node));
573194246Smarius
574194246Smarius  if (rlabel)
575194246Smarius    newnode->u.rlabel = rlabel;
576194246Smarius  else
577194246Smarius    newnode->u.tlabel = tlabel;
578194246Smarius  newnode->chain = *stack;
579194246Smarius  *stack = newnode;
580194246Smarius}
581194246Smarius
582194246Smarius/* Pop a label entry from the given STACK.  */
583194246Smarius
584194246Smariusrtx
585194246Smariuspop_label_entry (stack)
586194246Smarius     struct label_node **stack;
587194246Smarius{
588194246Smarius  rtx label;
589194246Smarius  struct label_node *tempnode;
590194246Smarius
591194246Smarius  if (! *stack)
592194246Smarius    return NULL_RTX;
593194246Smarius
594194246Smarius  tempnode = *stack;
595194246Smarius  label = tempnode->u.rlabel;
596194246Smarius  *stack = (*stack)->chain;
597194246Smarius  free (tempnode);
598194246Smarius
599194246Smarius  return label;
600194246Smarius}
601194246Smarius
602194246Smarius/* Return the top element of the given STACK.  */
603194246Smarius
604194246Smariustree
605194246Smariustop_label_entry (stack)
606194246Smarius     struct label_node **stack;
607194246Smarius{
608194246Smarius  if (! *stack)
609194246Smarius    return NULL_TREE;
610194246Smarius
611194246Smarius  return (*stack)->u.tlabel;
612194246Smarius}
613194246Smarius
614194246Smarius/* get an exception label. These must be on the permanent obstack */
615194246Smarius
616194246Smariusrtx
617194246Smariusgen_exception_label ()
618194246Smarius{
619194246Smarius  rtx lab;
620194246Smarius  lab = gen_label_rtx ();
621194246Smarius  return lab;
622194246Smarius}
623194246Smarius
624194246Smarius/* Push a new eh_node entry onto STACK.  */
625194246Smarius
626194246Smariusstatic void
627194246Smariuspush_eh_entry (stack)
628194246Smarius     struct eh_stack *stack;
629194246Smarius{
630194246Smarius  struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
631194246Smarius  struct eh_entry *entry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry));
632194246Smarius
633194246Smarius  rtx rlab = gen_exception_label ();
634194246Smarius  entry->finalization = NULL_TREE;
635194246Smarius  entry->label_used = 0;
636194904Smarius  entry->exception_handler_label = rlab;
637194246Smarius  entry->false_label = NULL_RTX;
638194246Smarius  if (! flag_new_exceptions)
639194246Smarius    entry->outer_context = gen_label_rtx ();
640194246Smarius  else
641194246Smarius    entry->outer_context = create_rethrow_ref (CODE_LABEL_NUMBER (rlab));
642194246Smarius  entry->rethrow_label = entry->outer_context;
643194246Smarius
644194246Smarius  node->entry = entry;
645194246Smarius  node->chain = stack->top;
646194246Smarius  stack->top = node;
647194246Smarius}
648194246Smarius
649194246Smarius/* push an existing entry onto a stack. */
650194246Smariusstatic void
651194246Smariuspush_entry (stack, entry)
652194246Smarius     struct eh_stack *stack;
653194246Smarius     struct eh_entry *entry;
654194246Smarius{
655194246Smarius  struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
656194246Smarius  node->entry = entry;
657194246Smarius  node->chain = stack->top;
658194246Smarius  stack->top = node;
659194246Smarius}
660194246Smarius
661194246Smarius/* Pop an entry from the given STACK.  */
662194246Smarius
663194246Smariusstatic struct eh_entry *
664194246Smariuspop_eh_entry (stack)
665194246Smarius     struct eh_stack *stack;
666194246Smarius{
667194246Smarius  struct eh_node *tempnode;
668194246Smarius  struct eh_entry *tempentry;
669194246Smarius
670194246Smarius  tempnode = stack->top;
671194904Smarius  tempentry = tempnode->entry;
672194904Smarius  stack->top = stack->top->chain;
673194246Smarius  free (tempnode);
674194904Smarius
675194904Smarius  return tempentry;
676194246Smarius}
677194246Smarius
678194246Smarius/* Enqueue an ENTRY onto the given QUEUE.  */
679194246Smarius
680194246Smariusstatic void
681194246Smariusenqueue_eh_entry (queue, entry)
682194246Smarius     struct eh_queue *queue;
683194246Smarius     struct eh_entry *entry;
684194246Smarius{
685194246Smarius  struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
686194246Smarius
687194246Smarius  node->entry = entry;
688194246Smarius  node->chain = NULL;
689194246Smarius
690194246Smarius  if (queue->head == NULL)
691194246Smarius    {
692194246Smarius      queue->head = node;
693194246Smarius    }
694194246Smarius  else
695194246Smarius    {
696194246Smarius      queue->tail->chain = node;
697194246Smarius    }
698194246Smarius  queue->tail = node;
699194246Smarius}
700194246Smarius
701194246Smarius/* Dequeue an entry from the given QUEUE.  */
702194246Smarius
703194246Smariusstatic struct eh_entry *
704194246Smariusdequeue_eh_entry (queue)
705194246Smarius     struct eh_queue *queue;
706194246Smarius{
707194246Smarius  struct eh_node *tempnode;
708194246Smarius  struct eh_entry *tempentry;
709194246Smarius
710194246Smarius  if (queue->head == NULL)
711194246Smarius    return NULL;
712194246Smarius
713194246Smarius  tempnode = queue->head;
714194246Smarius  queue->head = queue->head->chain;
715194246Smarius
716194246Smarius  tempentry = tempnode->entry;
717194246Smarius  free (tempnode);
718194246Smarius
719194246Smarius  return tempentry;
720194246Smarius}
721194246Smarius
722194246Smariusstatic void
723194246Smariusreceive_exception_label (handler_label)
724194246Smarius     rtx handler_label;
725194246Smarius{
726194246Smarius  emit_label (handler_label);
727194246Smarius
728194246Smarius#ifdef HAVE_exception_receiver
729194246Smarius  if (! exceptions_via_longjmp)
730194246Smarius    if (HAVE_exception_receiver)
731194246Smarius      emit_insn (gen_exception_receiver ());
732194246Smarius#endif
733194246Smarius
734194246Smarius#ifdef HAVE_nonlocal_goto_receiver
735194246Smarius  if (! exceptions_via_longjmp)
736194246Smarius    if (HAVE_nonlocal_goto_receiver)
737194246Smarius      emit_insn (gen_nonlocal_goto_receiver ());
738194246Smarius#endif
739194246Smarius}
740194246Smarius
741194246Smarius
742194246Smariusstruct func_eh_entry
743194246Smarius{
744194246Smarius  int range_number;   /* EH region number from EH NOTE insn's */
745194246Smarius  rtx rethrow_label;  /* Label for rethrow */
746194246Smarius  struct handler_info *handlers;
747194246Smarius};
748194246Smarius
749194246Smarius
750194246Smarius/* table of function eh regions */
751194246Smariusstatic struct func_eh_entry *function_eh_regions = NULL;
752194246Smariusstatic int num_func_eh_entries = 0;
753194246Smariusstatic int current_func_eh_entry = 0;
754194246Smarius
755194246Smarius#define SIZE_FUNC_EH(X)   (sizeof (struct func_eh_entry) * X)
756194246Smarius
757194246Smarius/* Add a new eh_entry for this function, and base it off of the information
758194246Smarius   in the EH_ENTRY parameter. A NULL parameter is invalid.
759194246Smarius   OUTER_CONTEXT is a label which is used for rethrowing. The number
760194246Smarius   returned is an number which uniquely identifies this exception range. */
761194246Smarius
762194246Smariusstatic int
763194246Smariusnew_eh_region_entry (note_eh_region, rethrow)
764194246Smarius     int note_eh_region;
765194246Smarius     rtx rethrow;
766194246Smarius{
767194246Smarius  if (current_func_eh_entry == num_func_eh_entries)
768194246Smarius    {
769194246Smarius      if (num_func_eh_entries == 0)
770194246Smarius        {
771223951Smarius          function_eh_regions =
772194246Smarius                        (struct func_eh_entry *) malloc (SIZE_FUNC_EH (50));
773194246Smarius          num_func_eh_entries = 50;
774194246Smarius        }
775194246Smarius      else
776194246Smarius        {
777194246Smarius          num_func_eh_entries  = num_func_eh_entries * 3 / 2;
778194246Smarius          function_eh_regions = (struct func_eh_entry *)
779194246Smarius            realloc (function_eh_regions, SIZE_FUNC_EH (num_func_eh_entries));
780194246Smarius        }
781194246Smarius    }
782194246Smarius  function_eh_regions[current_func_eh_entry].range_number = note_eh_region;
783223951Smarius  if (rethrow == NULL_RTX)
784194246Smarius    function_eh_regions[current_func_eh_entry].rethrow_label =
785194246Smarius                                          create_rethrow_ref (note_eh_region);
786194246Smarius  else
787194246Smarius    function_eh_regions[current_func_eh_entry].rethrow_label = rethrow;
788194246Smarius  function_eh_regions[current_func_eh_entry].handlers = NULL;
789194246Smarius
790194246Smarius  return current_func_eh_entry++;
791194246Smarius}
792194246Smarius
793194246Smarius/* Add new handler information to an exception range. The  first parameter
794194246Smarius   specifies the range number (returned from new_eh_entry()). The second
795194246Smarius   parameter specifies the handler.  By default the handler is inserted at
796194246Smarius   the end of the list. A handler list may contain only ONE NULL_TREE
797194246Smarius   typeinfo entry. Regardless where it is positioned, a NULL_TREE entry
798223951Smarius   is always output as the LAST handler in the exception table for a region. */
799194246Smarius
800194246Smariusvoid
801194246Smariusadd_new_handler (region, newhandler)
802194246Smarius     int region;
803194246Smarius     struct handler_info *newhandler;
804194246Smarius{
805194246Smarius  struct handler_info *last;
806194246Smarius
807194246Smarius  newhandler->next = NULL;
808194246Smarius  last = function_eh_regions[region].handlers;
809194246Smarius  if (last == NULL)
810223951Smarius    function_eh_regions[region].handlers = newhandler;
811194246Smarius  else
812194246Smarius    {
813194246Smarius      for ( ; ; last = last->next)
814194246Smarius	{
815194246Smarius	  if (last->type_info == CATCH_ALL_TYPE)
816194246Smarius	    pedwarn ("additional handler after ...");
817194246Smarius	  if (last->next == NULL)
818194246Smarius	    break;
819194246Smarius	}
820194246Smarius      last->next = newhandler;
821194246Smarius    }
822194246Smarius}
823194246Smarius
824194246Smarius/* Remove a handler label. The handler label is being deleted, so all
825223951Smarius   regions which reference this handler should have it removed from their
826223951Smarius   list of possible handlers. Any region which has the final handler
827247579Smarius   removed can be deleted. */
828247579Smarius
829223951Smariusvoid remove_handler (removing_label)
830194246Smarius     rtx removing_label;
831194246Smarius{
832194246Smarius  struct handler_info *handler, *last;
833194246Smarius  int x;
834194246Smarius  for (x = 0 ; x < current_func_eh_entry; ++x)
835194246Smarius    {
836194246Smarius      last = NULL;
837194246Smarius      handler = function_eh_regions[x].handlers;
838194246Smarius      for ( ; handler; last = handler, handler = handler->next)
839194246Smarius        if (handler->handler_label == removing_label)
840223951Smarius          {
841223951Smarius            if (last)
842247579Smarius              {
843247579Smarius                last->next = handler->next;
844223951Smarius                handler = last;
845194246Smarius              }
846194246Smarius            else
847194246Smarius              function_eh_regions[x].handlers = handler->next;
848194246Smarius          }
849194246Smarius    }
850194246Smarius}
851194246Smarius
852194246Smarius/* This function will return a malloc'd pointer to an array of
853194246Smarius   void pointer representing the runtime match values that
854194246Smarius   currently exist in all regions. */
855194246Smarius
856194246Smariusint
857194246Smariusfind_all_handler_type_matches (array)
858194246Smarius  void ***array;
859194246Smarius{
860194246Smarius  struct handler_info *handler, *last;
861194246Smarius  int x,y;
862194246Smarius  void *val;
863194246Smarius  void **ptr;
864194246Smarius  int max_ptr;
865194246Smarius  int n_ptr = 0;
866194246Smarius
867194246Smarius  *array = NULL;
868194246Smarius
869194246Smarius  if (!doing_eh (0) || ! flag_new_exceptions)
870194246Smarius    return 0;
871194246Smarius
872194246Smarius  max_ptr = 100;
873194246Smarius  ptr = (void **)malloc (max_ptr * sizeof (void *));
874194246Smarius
875194246Smarius  if (ptr == NULL)
876194246Smarius    return 0;
877194246Smarius
878194246Smarius  for (x = 0 ; x < current_func_eh_entry; x++)
879194246Smarius    {
880194246Smarius      last = NULL;
881194246Smarius      handler = function_eh_regions[x].handlers;
882194246Smarius      for ( ; handler; last = handler, handler = handler->next)
883194246Smarius        {
884194246Smarius          val = handler->type_info;
885194246Smarius          if (val != NULL && val != CATCH_ALL_TYPE)
886194246Smarius            {
887194246Smarius              /* See if this match value has already been found. */
888194246Smarius              for (y = 0; y < n_ptr; y++)
889194246Smarius                if (ptr[y] == val)
890194246Smarius                  break;
891194246Smarius
892194246Smarius              /* If we break early, we already found this value. */
893194246Smarius              if (y < n_ptr)
894194246Smarius                continue;
895194246Smarius
896194246Smarius              /* Do we need to allocate more space? */
897194246Smarius              if (n_ptr >= max_ptr)
898194246Smarius                {
899194246Smarius                  max_ptr += max_ptr / 2;
900194246Smarius                  ptr = (void **)realloc (ptr, max_ptr * sizeof (void *));
901194246Smarius                  if (ptr == NULL)
902194246Smarius                    return 0;
903194246Smarius                }
904194246Smarius              ptr[n_ptr] = val;
905194246Smarius              n_ptr++;
906194246Smarius            }
907194246Smarius        }
908194246Smarius    }
909194246Smarius  *array = ptr;
910194246Smarius  return n_ptr;
911194246Smarius}
912194246Smarius
913194246Smarius/* Create a new handler structure initialized with the handler label and
914194246Smarius   typeinfo fields passed in. */
915194246Smarius
916194246Smariusstruct handler_info *
917194246Smariusget_new_handler (handler, typeinfo)
918194246Smarius     rtx handler;
919194246Smarius     void *typeinfo;
920194246Smarius{
921194246Smarius  struct handler_info* ptr;
922194246Smarius  ptr = (struct handler_info *) malloc (sizeof (struct handler_info));
923194246Smarius  ptr->handler_label = handler;
924194246Smarius  ptr->handler_number = CODE_LABEL_NUMBER (handler);
925194246Smarius  ptr->type_info = typeinfo;
926194246Smarius  ptr->next = NULL;
927194246Smarius
928194246Smarius  return ptr;
929194246Smarius}
930194246Smarius
931194246Smarius
932194246Smarius
933194246Smarius/* Find the index in function_eh_regions associated with a NOTE region. If
934194246Smarius   the region cannot be found, a -1 is returned. This should never happen! */
935194246Smarius
936194246Smariusint
937194246Smariusfind_func_region (insn_region)
938194246Smarius     int insn_region;
939194246Smarius{
940194246Smarius  int x;
941194246Smarius  for (x = 0; x < current_func_eh_entry; x++)
942194246Smarius    if (function_eh_regions[x].range_number == insn_region)
943194246Smarius      return x;
944194246Smarius
945194246Smarius  return -1;
946194246Smarius}
947194246Smarius
948194246Smarius/* Get a pointer to the first handler in an exception region's list. */
949194246Smarius
950194246Smariusstruct handler_info *
951194246Smariusget_first_handler (region)
952194246Smarius     int region;
953194246Smarius{
954194246Smarius  return function_eh_regions[find_func_region (region)].handlers;
955194246Smarius}
956194246Smarius
957194246Smarius/* Clean out the function_eh_region table and free all memory */
958194246Smarius
959194246Smariusstatic void
960194246Smariusclear_function_eh_region ()
961194246Smarius{
962194246Smarius  int x;
963194246Smarius  struct handler_info *ptr, *next;
964194246Smarius  for (x = 0; x < current_func_eh_entry; x++)
965194246Smarius    for (ptr = function_eh_regions[x].handlers; ptr != NULL; ptr = next)
966194246Smarius      {
967194246Smarius        next = ptr->next;
968194246Smarius        free (ptr);
969194246Smarius      }
970194246Smarius  free (function_eh_regions);
971194246Smarius  num_func_eh_entries  = 0;
972194246Smarius  current_func_eh_entry = 0;
973194246Smarius}
974194904Smarius
975194904Smarius/* Make a duplicate of an exception region by copying all the handlers
976194904Smarius   for an exception region. Return the new handler index. The final
977194246Smarius   parameter is a routine which maps old labels to new ones. */
978194246Smarius
979194246Smariusint
980194246Smariusduplicate_eh_handlers (old_note_eh_region, new_note_eh_region, map)
981194246Smarius     int old_note_eh_region, new_note_eh_region;
982194246Smarius     rtx (*map) PARAMS ((rtx));
983194246Smarius{
984194246Smarius  struct handler_info *ptr, *new_ptr;
985194246Smarius  int new_region, region;
986194246Smarius
987194246Smarius  region = find_func_region (old_note_eh_region);
988194246Smarius  if (region == -1)
989194246Smarius    fatal ("Cannot duplicate non-existant exception region.");
990194246Smarius
991194246Smarius  /* duplicate_eh_handlers may have been called during a symbol remap. */
992194246Smarius  new_region = find_func_region (new_note_eh_region);
993194246Smarius  if (new_region != -1)
994194246Smarius    return (new_region);
995194246Smarius
996207585Smarius  new_region = new_eh_region_entry (new_note_eh_region, NULL_RTX);
997207585Smarius
998207585Smarius  ptr = function_eh_regions[region].handlers;
999194246Smarius
1000194246Smarius  for ( ; ptr; ptr = ptr->next)
1001194246Smarius    {
1002194246Smarius      new_ptr = get_new_handler (map (ptr->handler_label), ptr->type_info);
1003194246Smarius      add_new_handler (new_region, new_ptr);
1004194246Smarius    }
1005194246Smarius
1006194246Smarius  return new_region;
1007194246Smarius}
1008194246Smarius
1009194246Smarius
1010194246Smarius/* Given a rethrow symbol, find the EH region number this is for. */
1011194246Smariusint
1012194246Smariuseh_region_from_symbol (sym)
1013194246Smarius     rtx sym;
1014194246Smarius{
1015194246Smarius  int x;
1016194246Smarius  if (sym == last_rethrow_symbol)
1017194246Smarius    return 1;
1018194246Smarius  for (x = 0; x < current_func_eh_entry; x++)
1019194246Smarius    if (function_eh_regions[x].rethrow_label == sym)
1020194246Smarius      return function_eh_regions[x].range_number;
1021194246Smarius  return -1;
1022194246Smarius}
1023194246Smarius
1024194246Smarius
1025194246Smarius/* When inlining/unrolling, we have to map the symbols passed to
1026194246Smarius   __rethrow as well. This performs the remap. If a symbol isn't foiund,
1027194246Smarius   the original one is returned. This is not an efficient routine,
1028194246Smarius   so don't call it on everything!! */
1029194246Smariusrtx
1030194246Smariusrethrow_symbol_map (sym, map)
1031194246Smarius     rtx sym;
1032194246Smarius     rtx (*map) PARAMS ((rtx));
1033194246Smarius{
1034194246Smarius  int x, y;
1035194246Smarius  for (x = 0; x < current_func_eh_entry; x++)
1036194246Smarius    if (function_eh_regions[x].rethrow_label == sym)
1037194246Smarius      {
1038194246Smarius        /* We've found the original region, now lets determine which region
1039194246Smarius           this now maps to. */
1040194246Smarius        rtx l1 = function_eh_regions[x].handlers->handler_label;
1041194246Smarius        rtx l2 = map (l1);
1042194246Smarius        y = CODE_LABEL_NUMBER (l2); /* This is the new region number */
1043194246Smarius        x = find_func_region (y);  /* Get the new permanent region */
1044194246Smarius        if (x == -1)  /* Hmm, Doesn't exist yet */
1045194246Smarius          {
1046247579Smarius            x = duplicate_eh_handlers (CODE_LABEL_NUMBER (l1), y, map);
1047247579Smarius            /* Since we're mapping it, it must be used. */
1048194246Smarius            SYMBOL_REF_USED (function_eh_regions[x].rethrow_label) = 1;
1049194246Smarius          }
1050194246Smarius        return function_eh_regions[x].rethrow_label;
1051194246Smarius      }
1052194246Smarius  return sym;
1053194246Smarius}
1054194246Smarius
1055194246Smariusint
1056194246Smariusrethrow_used (region)
1057194904Smarius     int region;
1058194246Smarius{
1059194246Smarius  if (flag_new_exceptions)
1060194246Smarius    {
1061194246Smarius      rtx lab = function_eh_regions[find_func_region (region)].rethrow_label;
1062194246Smarius      return (SYMBOL_REF_USED (lab));
1063194246Smarius    }
1064194246Smarius  return 0;
1065194246Smarius}
1066194904Smarius
1067194904Smarius
1068194246Smarius/* Routine to see if exception handling is turned on.
1069194246Smarius   DO_WARN is non-zero if we want to inform the user that exception
1070194246Smarius   handling is turned off.
1071194246Smarius
1072194246Smarius   This is used to ensure that -fexceptions has been specified if the
1073194246Smarius   compiler tries to use any exception-specific functions.  */
1074194246Smarius
1075194246Smariusint
1076194246Smariusdoing_eh (do_warn)
1077194246Smarius     int do_warn;
1078194246Smarius{
1079194246Smarius  if (! flag_exceptions)
1080194246Smarius    {
1081194246Smarius      static int warned = 0;
1082194246Smarius      if (! warned && do_warn)
1083194246Smarius	{
1084194246Smarius	  error ("exception handling disabled, use -fexceptions to enable");
1085194246Smarius	  warned = 1;
1086194246Smarius	}
1087194246Smarius      return 0;
1088194246Smarius    }
1089194246Smarius  return 1;
1090194246Smarius}
1091194246Smarius
1092194246Smarius/* Given a return address in ADDR, determine the address we should use
1093194246Smarius   to find the corresponding EH region.  */
1094194246Smarius
1095194246Smariusrtx
1096194246Smariuseh_outer_context (addr)
1097194246Smarius     rtx addr;
1098194246Smarius{
1099194246Smarius  /* First mask out any unwanted bits.  */
1100194246Smarius#ifdef MASK_RETURN_ADDR
1101194246Smarius  expand_and (addr, MASK_RETURN_ADDR, addr);
1102194246Smarius#endif
1103194246Smarius
1104194246Smarius  /* Then adjust to find the real return address.  */
1105194246Smarius#if defined (RETURN_ADDR_OFFSET)
1106194246Smarius  addr = plus_constant (addr, RETURN_ADDR_OFFSET);
1107194246Smarius#endif
1108194246Smarius
1109194246Smarius  return addr;
1110194246Smarius}
1111194246Smarius
1112194246Smarius/* Start a new exception region for a region of code that has a
1113215721Smarius   cleanup action and push the HANDLER for the region onto
1114194246Smarius   protect_list. All of the regions created with add_partial_entry
1115194246Smarius   will be ended when end_protect_partials is invoked.  */
1116194246Smarius
1117194246Smariusvoid
1118194246Smariusadd_partial_entry (handler)
1119194246Smarius     tree handler;
1120194246Smarius{
1121194246Smarius  expand_eh_region_start ();
1122194246Smarius
1123194246Smarius  /* Make sure the entry is on the correct obstack.  */
1124194246Smarius  push_obstacks_nochange ();
1125194246Smarius  resume_temporary_allocation ();
1126194246Smarius
1127194246Smarius  /* Because this is a cleanup action, we may have to protect the handler
1128194246Smarius     with __terminate.  */
1129194246Smarius  handler = protect_with_terminate (handler);
1130194246Smarius
1131194246Smarius  protect_list = tree_cons (NULL_TREE, handler, protect_list);
1132194246Smarius  pop_obstacks ();
1133194246Smarius}
1134194246Smarius
1135194246Smarius/* Emit code to get EH context to current function.  */
1136194246Smarius
1137194246Smariusstatic rtx
1138194246Smariuscall_get_eh_context ()
1139194246Smarius{
1140194246Smarius  static tree fn;
1141194246Smarius  tree expr;
1142194246Smarius
1143194246Smarius  if (fn == NULL_TREE)
1144194246Smarius    {
1145194246Smarius      tree fntype;
1146194246Smarius      fn = get_identifier ("__get_eh_context");
1147194246Smarius      push_obstacks_nochange ();
1148194246Smarius      end_temporary_allocation ();
1149194246Smarius      fntype = build_pointer_type (build_pointer_type
1150194246Smarius				   (build_pointer_type (void_type_node)));
1151194246Smarius      fntype = build_function_type (fntype, NULL_TREE);
1152223951Smarius      fn = build_decl (FUNCTION_DECL, fn, fntype);
1153223951Smarius      DECL_EXTERNAL (fn) = 1;
1154223951Smarius      TREE_PUBLIC (fn) = 1;
1155223951Smarius      DECL_ARTIFICIAL (fn) = 1;
1156223951Smarius      TREE_READONLY (fn) = 1;
1157223951Smarius      make_decl_rtl (fn, NULL_PTR, 1);
1158223951Smarius      assemble_external (fn);
1159223951Smarius      pop_obstacks ();
1160223951Smarius    }
1161194246Smarius
1162194246Smarius  expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
1163194246Smarius  expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
1164194246Smarius		expr, NULL_TREE, NULL_TREE);
1165223951Smarius  TREE_SIDE_EFFECTS (expr) = 1;
1166194246Smarius
1167194246Smarius  return copy_to_reg (expand_expr (expr, NULL_RTX, VOIDmode, 0));
1168194246Smarius}
1169194246Smarius
1170220943Smarius/* Get a reference to the EH context.
1171194246Smarius   We will only generate a register for the current function EH context here,
1172194246Smarius   and emit a USE insn to mark that this is a EH context register.
1173194246Smarius
1174194246Smarius   Later, emit_eh_context will emit needed call to __get_eh_context
1175194246Smarius   in libgcc2, and copy the value to the register we have generated. */
1176194246Smarius
1177194246Smariusrtx
1178194246Smariusget_eh_context ()
1179194246Smarius{
1180194246Smarius  if (current_function_ehc == 0)
1181194246Smarius    {
1182194246Smarius      rtx insn;
1183194246Smarius
1184194246Smarius      current_function_ehc = gen_reg_rtx (Pmode);
1185194246Smarius
1186194246Smarius      insn = gen_rtx_USE (GET_MODE (current_function_ehc),
1187194246Smarius			  current_function_ehc);
1188194246Smarius      insn = emit_insn_before (insn, get_first_nonparm_insn ());
1189194246Smarius
1190194246Smarius      REG_NOTES (insn)
1191194246Smarius	= gen_rtx_EXPR_LIST (REG_EH_CONTEXT, current_function_ehc,
1192194246Smarius			     REG_NOTES (insn));
1193194246Smarius    }
1194194246Smarius  return current_function_ehc;
1195194246Smarius}
1196194246Smarius
1197194246Smarius/* Get a reference to the dynamic handler chain.  It points to the
1198194246Smarius   pointer to the next element in the dynamic handler chain.  It ends
1199194246Smarius   when there are no more elements in the dynamic handler chain, when
1200194246Smarius   the value is &top_elt from libgcc2.c.  Immediately after the
1201194246Smarius   pointer, is an area suitable for setjmp/longjmp when
1202194246Smarius   DONT_USE_BUILTIN_SETJMP is defined, and an area suitable for
1203194246Smarius   __builtin_setjmp/__builtin_longjmp when DONT_USE_BUILTIN_SETJMP
1204194246Smarius   isn't defined. */
1205194246Smarius
1206194246Smariusrtx
1207243857Sglebiusget_dynamic_handler_chain ()
1208194246Smarius{
1209194246Smarius  rtx ehc, dhc, result;
1210194246Smarius
1211194246Smarius  ehc = get_eh_context ();
1212194246Smarius
1213194246Smarius  /* This is the offset of dynamic_handler_chain in the eh_context struct
1214194246Smarius     declared in eh-common.h. If its location is change, change this offset */
1215194246Smarius  dhc = plus_constant (ehc, POINTER_SIZE / BITS_PER_UNIT);
1216194246Smarius
1217194246Smarius  result = copy_to_reg (dhc);
1218194246Smarius
1219194246Smarius  /* We don't want a copy of the dcc, but rather, the single dcc.  */
1220194246Smarius  return gen_rtx_MEM (Pmode, result);
1221194246Smarius}
1222194246Smarius
1223194246Smarius/* Get a reference to the dynamic cleanup chain.  It points to the
1224194246Smarius   pointer to the next element in the dynamic cleanup chain.
1225194246Smarius   Immediately after the pointer, are two Pmode variables, one for a
1226194246Smarius   pointer to a function that performs the cleanup action, and the
1227194246Smarius   second, the argument to pass to that function.  */
1228194246Smarius
1229194246Smariusrtx
1230243857Sglebiusget_dynamic_cleanup_chain ()
1231194246Smarius{
1232194246Smarius  rtx dhc, dcc, result;
1233194246Smarius
1234194246Smarius  dhc = get_dynamic_handler_chain ();
1235194246Smarius  dcc = plus_constant (dhc, POINTER_SIZE / BITS_PER_UNIT);
1236194246Smarius
1237194246Smarius  result = copy_to_reg (dcc);
1238194246Smarius
1239194246Smarius  /* We don't want a copy of the dcc, but rather, the single dcc.  */
1240194246Smarius  return gen_rtx_MEM (Pmode, result);
1241194246Smarius}
1242194246Smarius
1243194246Smarius#ifdef DONT_USE_BUILTIN_SETJMP
1244194246Smarius/* Generate code to evaluate X and jump to LABEL if the value is nonzero.
1245194246Smarius   LABEL is an rtx of code CODE_LABEL, in this function.  */
1246194246Smarius
1247194246Smariusstatic void
1248194246Smariusjumpif_rtx (x, label)
1249194246Smarius     rtx x;
1250194246Smarius     rtx label;
1251194246Smarius{
1252194246Smarius  jumpif (make_tree (type_for_mode (GET_MODE (x), 0), x), label);
1253194246Smarius}
1254194246Smarius#endif
1255194246Smarius
1256194246Smarius/* Start a dynamic cleanup on the EH runtime dynamic cleanup stack.
1257194246Smarius   We just need to create an element for the cleanup list, and push it
1258194246Smarius   into the chain.
1259194246Smarius
1260194246Smarius   A dynamic cleanup is a cleanup action implied by the presence of an
1261194246Smarius   element on the EH runtime dynamic cleanup stack that is to be
1262194246Smarius   performed when an exception is thrown.  The cleanup action is
1263194246Smarius   performed by __sjthrow when an exception is thrown.  Only certain
1264194246Smarius   actions can be optimized into dynamic cleanup actions.  For the
1265194246Smarius   restrictions on what actions can be performed using this routine,
1266194246Smarius   see expand_eh_region_start_tree.  */
1267194246Smarius
1268194246Smariusstatic void
1269194246Smariusstart_dynamic_cleanup (func, arg)
1270194246Smarius     tree func;
1271194246Smarius     tree arg;
1272194246Smarius{
1273194246Smarius  rtx dcc;
1274194246Smarius  rtx new_func, new_arg;
1275194246Smarius  rtx x, buf;
1276194246Smarius  int size;
1277194246Smarius
1278194246Smarius  /* We allocate enough room for a pointer to the function, and
1279194246Smarius     one argument.  */
1280194246Smarius  size = 2;
1281194246Smarius
1282194246Smarius  /* XXX, FIXME: The stack space allocated this way is too long lived,
1283194246Smarius     but there is no allocation routine that allocates at the level of
1284194246Smarius     the last binding contour.  */
1285194246Smarius  buf = assign_stack_local (BLKmode,
1286194246Smarius			    GET_MODE_SIZE (Pmode)*(size+1),
1287194246Smarius			    0);
1288194246Smarius
1289194246Smarius  buf = change_address (buf, Pmode, NULL_RTX);
1290194246Smarius
1291194246Smarius  /* Store dcc into the first word of the newly allocated buffer.  */
1292194246Smarius
1293194246Smarius  dcc = get_dynamic_cleanup_chain ();
1294194246Smarius  emit_move_insn (buf, dcc);
1295194246Smarius
1296194246Smarius  /* Store func and arg into the cleanup list element.  */
1297194246Smarius
1298194246Smarius  new_func = gen_rtx_MEM (Pmode, plus_constant (XEXP (buf, 0),
1299194246Smarius						GET_MODE_SIZE (Pmode)));
1300194246Smarius  new_arg = gen_rtx_MEM (Pmode, plus_constant (XEXP (buf, 0),
1301194904Smarius					       GET_MODE_SIZE (Pmode)*2));
1302194246Smarius  x = expand_expr (func, new_func, Pmode, 0);
1303194246Smarius  if (x != new_func)
1304194246Smarius    emit_move_insn (new_func, x);
1305194246Smarius
1306194246Smarius  x = expand_expr (arg, new_arg, Pmode, 0);
1307194246Smarius  if (x != new_arg)
1308194246Smarius    emit_move_insn (new_arg, x);
1309194246Smarius
1310194246Smarius  /* Update the cleanup chain.  */
1311194246Smarius
1312194246Smarius  emit_move_insn (dcc, XEXP (buf, 0));
1313194246Smarius}
1314194246Smarius
1315194246Smarius/* Emit RTL to start a dynamic handler on the EH runtime dynamic
1316194246Smarius   handler stack.  This should only be used by expand_eh_region_start
1317194246Smarius   or expand_eh_region_start_tree.  */
1318194246Smarius
1319194246Smariusstatic void
1320194246Smariusstart_dynamic_handler ()
1321194246Smarius{
1322194246Smarius  rtx dhc, dcc;
1323194246Smarius  rtx x, arg, buf;
1324194246Smarius  int size;
1325194246Smarius
1326194246Smarius#ifndef DONT_USE_BUILTIN_SETJMP
1327194246Smarius  /* The number of Pmode words for the setjmp buffer, when using the
1328194246Smarius     builtin setjmp/longjmp, see expand_builtin, case
1329194246Smarius     BUILT_IN_LONGJMP.  */
1330194246Smarius  size = 5;
1331194246Smarius#else
1332194246Smarius#ifdef JMP_BUF_SIZE
1333194246Smarius  size = JMP_BUF_SIZE;
1334194246Smarius#else
1335194246Smarius  /* Should be large enough for most systems, if it is not,
1336194246Smarius     JMP_BUF_SIZE should be defined with the proper value.  It will
1337194246Smarius     also tend to be larger than necessary for most systems, a more
1338194246Smarius     optimal port will define JMP_BUF_SIZE.  */
1339194246Smarius  size = FIRST_PSEUDO_REGISTER+2;
1340194246Smarius#endif
1341194246Smarius#endif
1342194246Smarius  /* XXX, FIXME: The stack space allocated this way is too long lived,
1343194246Smarius     but there is no allocation routine that allocates at the level of
1344194246Smarius     the last binding contour.  */
1345194246Smarius  arg = assign_stack_local (BLKmode,
1346194246Smarius			    GET_MODE_SIZE (Pmode)*(size+1),
1347194246Smarius			    0);
1348194246Smarius
1349194246Smarius  arg = change_address (arg, Pmode, NULL_RTX);
1350194246Smarius
1351194246Smarius  /* Store dhc into the first word of the newly allocated buffer.  */
1352194246Smarius
1353194246Smarius  dhc = get_dynamic_handler_chain ();
1354194246Smarius  dcc = gen_rtx_MEM (Pmode, plus_constant (XEXP (arg, 0),
1355215721Smarius					   GET_MODE_SIZE (Pmode)));
1356194246Smarius  emit_move_insn (arg, dhc);
1357194246Smarius
1358194246Smarius  /* Zero out the start of the cleanup chain.  */
1359194246Smarius  emit_move_insn (dcc, const0_rtx);
1360194246Smarius
1361194246Smarius  /* The jmpbuf starts two words into the area allocated.  */
1362194246Smarius  buf = plus_constant (XEXP (arg, 0), GET_MODE_SIZE (Pmode)*2);
1363194246Smarius
1364194246Smarius#ifdef DONT_USE_BUILTIN_SETJMP
1365194246Smarius  x = emit_library_call_value (setjmp_libfunc, NULL_RTX, 1, SImode, 1,
1366194246Smarius			       buf, Pmode);
1367194246Smarius  /* If we come back here for a catch, transfer control to the handler.  */
1368194246Smarius  jumpif_rtx (x, ehstack.top->entry->exception_handler_label);
1369194246Smarius#else
1370194246Smarius  {
1371194246Smarius    /* A label to continue execution for the no exception case.  */
1372194246Smarius    rtx noex = gen_label_rtx();
1373194246Smarius    x = expand_builtin_setjmp (buf, NULL_RTX, noex,
1374194246Smarius			       ehstack.top->entry->exception_handler_label);
1375194246Smarius    emit_label (noex);
1376194246Smarius  }
1377194246Smarius#endif
1378194246Smarius
1379194246Smarius  /* We are committed to this, so update the handler chain.  */
1380194246Smarius
1381194246Smarius  emit_move_insn (dhc, force_operand (XEXP (arg, 0), NULL_RTX));
1382194246Smarius}
1383194246Smarius
1384194246Smarius/* Start an exception handling region for the given cleanup action.
1385194246Smarius   All instructions emitted after this point are considered to be part
1386194246Smarius   of the region until expand_eh_region_end is invoked.  CLEANUP is
1387194246Smarius   the cleanup action to perform.  The return value is true if the
1388194246Smarius   exception region was optimized away.  If that case,
1389194246Smarius   expand_eh_region_end does not need to be called for this cleanup,
1390194246Smarius   nor should it be.
1391194246Smarius
1392194246Smarius   This routine notices one particular common case in C++ code
1393194246Smarius   generation, and optimizes it so as to not need the exception
1394194246Smarius   region.  It works by creating a dynamic cleanup action, instead of
1395194246Smarius   a using an exception region.  */
1396194246Smarius
1397194246Smariusint
1398194246Smariusexpand_eh_region_start_tree (decl, cleanup)
1399194246Smarius     tree decl;
1400194246Smarius     tree cleanup;
1401194246Smarius{
1402194246Smarius  /* This is the old code.  */
1403194246Smarius  if (! doing_eh (0))
1404194246Smarius    return 0;
1405194246Smarius
1406194246Smarius  /* The optimization only applies to actions protected with
1407194246Smarius     terminate, and only applies if we are using the setjmp/longjmp
1408194246Smarius     codegen method.  */
1409194246Smarius  if (exceptions_via_longjmp
1410194246Smarius      && protect_cleanup_actions_with_terminate)
1411194246Smarius    {
1412194904Smarius      tree func, arg;
1413194246Smarius      tree args;
1414194904Smarius
1415194246Smarius      /* Ignore any UNSAVE_EXPR.  */
1416194904Smarius      if (TREE_CODE (cleanup) == UNSAVE_EXPR)
1417194904Smarius	cleanup = TREE_OPERAND (cleanup, 0);
1418194246Smarius
1419194246Smarius      /* Further, it only applies if the action is a call, if there
1420194246Smarius	 are 2 arguments, and if the second argument is 2.  */
1421194246Smarius
1422194246Smarius      if (TREE_CODE (cleanup) == CALL_EXPR
1423194246Smarius	  && (args = TREE_OPERAND (cleanup, 1))
1424194246Smarius	  && (func = TREE_OPERAND (cleanup, 0))
1425194246Smarius	  && (arg = TREE_VALUE (args))
1426194246Smarius	  && (args = TREE_CHAIN (args))
1427194246Smarius
1428194246Smarius	  /* is the second argument 2?  */
1429194246Smarius	  && TREE_CODE (TREE_VALUE (args)) == INTEGER_CST
1430194246Smarius	  && TREE_INT_CST_LOW (TREE_VALUE (args)) == 2
1431194246Smarius	  && TREE_INT_CST_HIGH (TREE_VALUE (args)) == 0
1432194246Smarius
1433194246Smarius	  /* Make sure there are no other arguments.  */
1434194246Smarius	  && TREE_CHAIN (args) == NULL_TREE)
1435194246Smarius	{
1436194246Smarius	  /* Arrange for returns and gotos to pop the entry we make on the
1437194246Smarius	     dynamic cleanup stack.  */
1438194246Smarius	  expand_dcc_cleanup (decl);
1439194904Smarius	  start_dynamic_cleanup (func, arg);
1440194246Smarius	  return 1;
1441194246Smarius	}
1442194246Smarius    }
1443194246Smarius
1444194246Smarius  expand_eh_region_start_for_decl (decl);
1445194904Smarius  ehstack.top->entry->finalization = cleanup;
1446194246Smarius
1447194246Smarius  return 0;
1448194904Smarius}
1449194904Smarius
1450194246Smarius/* Just like expand_eh_region_start, except if a cleanup action is
1451194904Smarius   entered on the cleanup chain, the TREE_PURPOSE of the element put
1452194246Smarius   on the chain is DECL.  DECL should be the associated VAR_DECL, if
1453194904Smarius   any, otherwise it should be NULL_TREE.  */
1454194904Smarius
1455194904Smariusvoid
1456194246Smariusexpand_eh_region_start_for_decl (decl)
1457194246Smarius     tree decl;
1458194246Smarius{
1459194246Smarius  rtx note;
1460194246Smarius
1461194246Smarius  /* This is the old code.  */
1462194246Smarius  if (! doing_eh (0))
1463194246Smarius    return;
1464194246Smarius
1465194246Smarius  if (exceptions_via_longjmp)
1466194246Smarius    {
1467194246Smarius      /* We need a new block to record the start and end of the
1468194246Smarius	 dynamic handler chain.  We could always do this, but we
1469194246Smarius	 really want to permit jumping into such a block, and we want
1470194246Smarius	 to avoid any errors or performance impact in the SJ EH code
1471194246Smarius	 for now.  */
1472194246Smarius      expand_start_bindings (0);
1473194246Smarius
1474194246Smarius      /* But we don't need or want a new temporary level.  */
1475194246Smarius      pop_temp_slots ();
1476194246Smarius
1477194246Smarius      /* Mark this block as created by expand_eh_region_start.  This
1478194246Smarius	 is so that we can pop the block with expand_end_bindings
1479194246Smarius	 automatically.  */
1480194246Smarius      mark_block_as_eh_region ();
1481194246Smarius
1482194246Smarius      /* Arrange for returns and gotos to pop the entry we make on the
1483194246Smarius	 dynamic handler stack.  */
1484194246Smarius      expand_dhc_cleanup (decl);
1485194246Smarius    }
1486194246Smarius
1487194246Smarius  push_eh_entry (&ehstack);
1488194246Smarius  note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_BEG);
1489194246Smarius  NOTE_BLOCK_NUMBER (note)
1490194246Smarius    = CODE_LABEL_NUMBER (ehstack.top->entry->exception_handler_label);
1491194246Smarius  if (exceptions_via_longjmp)
1492194246Smarius    start_dynamic_handler ();
1493194246Smarius}
1494194246Smarius
1495194246Smarius/* Start an exception handling region.  All instructions emitted after
1496194246Smarius   this point are considered to be part of the region until
1497194246Smarius   expand_eh_region_end is invoked.  */
1498194246Smarius
1499194904Smariusvoid
1500194904Smariusexpand_eh_region_start ()
1501194246Smarius{
1502194246Smarius  expand_eh_region_start_for_decl (NULL_TREE);
1503194246Smarius}
1504194246Smarius
1505194246Smarius/* End an exception handling region.  The information about the region
1506194246Smarius   is found on the top of ehstack.
1507194246Smarius
1508194246Smarius   HANDLER is either the cleanup for the exception region, or if we're
1509194246Smarius   marking the end of a try block, HANDLER is integer_zero_node.
1510194246Smarius
1511194246Smarius   HANDLER will be transformed to rtl when expand_leftover_cleanups
1512194246Smarius   is invoked.  */
1513194246Smarius
1514194246Smariusvoid
1515194246Smariusexpand_eh_region_end (handler)
1516194246Smarius     tree handler;
1517194246Smarius{
1518194246Smarius  struct eh_entry *entry;
1519194246Smarius  rtx note;
1520194246Smarius  int ret, r;
1521194246Smarius
1522194246Smarius  if (! doing_eh (0))
1523194246Smarius    return;
1524194246Smarius
1525194246Smarius  entry = pop_eh_entry (&ehstack);
1526194246Smarius
1527194246Smarius  note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END);
1528194246Smarius  ret = NOTE_BLOCK_NUMBER (note)
1529194246Smarius    = CODE_LABEL_NUMBER (entry->exception_handler_label);
1530194246Smarius  if (exceptions_via_longjmp == 0 && ! flag_new_exceptions
1531194246Smarius      /* We share outer_context between regions; only emit it once.  */
1532194246Smarius      && INSN_UID (entry->outer_context) == 0)
1533194246Smarius    {
1534194246Smarius      rtx label;
1535194246Smarius
1536194246Smarius      label = gen_label_rtx ();
1537194246Smarius      emit_jump (label);
1538194246Smarius
1539194246Smarius      /* Emit a label marking the end of this exception region that
1540194246Smarius	 is used for rethrowing into the outer context.  */
1541194246Smarius      emit_label (entry->outer_context);
1542194246Smarius      expand_internal_throw ();
1543194246Smarius
1544194246Smarius      emit_label (label);
1545194246Smarius    }
1546194246Smarius
1547194246Smarius  entry->finalization = handler;
1548194246Smarius
1549194246Smarius  /* create region entry in final exception table */
1550194246Smarius  r = new_eh_region_entry (NOTE_BLOCK_NUMBER (note), entry->rethrow_label);
1551194246Smarius
1552194246Smarius  enqueue_eh_entry (&ehqueue, entry);
1553194246Smarius
1554194246Smarius  /* If we have already started ending the bindings, don't recurse.
1555194246Smarius     This only happens when exceptions_via_longjmp is true.  */
1556194246Smarius  if (is_eh_region ())
1557194246Smarius    {
1558194246Smarius      /* Because we don't need or want a new temporary level and
1559194246Smarius	 because we didn't create one in expand_eh_region_start,
1560194246Smarius	 create a fake one now to avoid removing one in
1561194246Smarius	 expand_end_bindings.  */
1562194246Smarius      push_temp_slots ();
1563194246Smarius
1564194246Smarius      mark_block_as_not_eh_region ();
1565194246Smarius
1566194246Smarius      /* Maybe do this to prevent jumping in and so on...  */
1567194246Smarius      expand_end_bindings (NULL_TREE, 0, 0);
1568194246Smarius    }
1569194246Smarius}
1570194246Smarius
1571194246Smarius/* End the EH region for a goto fixup.  We only need them in the region-based
1572194246Smarius   EH scheme.  */
1573194246Smarius
1574194246Smariusvoid
1575194246Smariusexpand_fixup_region_start ()
1576194246Smarius{
1577194246Smarius  if (! doing_eh (0) || exceptions_via_longjmp)
1578194246Smarius    return;
1579194246Smarius
1580194246Smarius  expand_eh_region_start ();
1581194246Smarius}
1582194246Smarius
1583194246Smarius/* End the EH region for a goto fixup.  CLEANUP is the cleanup we just
1584194246Smarius   expanded; to avoid running it twice if it throws, we look through the
1585194246Smarius   ehqueue for a matching region and rethrow from its outer_context.  */
1586194246Smarius
1587194246Smariusvoid
1588215721Smariusexpand_fixup_region_end (cleanup)
1589194246Smarius     tree cleanup;
1590215721Smarius{
1591215721Smarius  struct eh_node *node;
1592215721Smarius  int dont_issue;
1593194246Smarius
1594194246Smarius  if (! doing_eh (0) || exceptions_via_longjmp)
1595194246Smarius    return;
1596194246Smarius
1597194904Smarius  for (node = ehstack.top; node && node->entry->finalization != cleanup; )
1598194246Smarius    node = node->chain;
1599194246Smarius  if (node == 0)
1600194246Smarius    for (node = ehqueue.head; node && node->entry->finalization != cleanup; )
1601194246Smarius      node = node->chain;
1602194246Smarius  if (node == 0)
1603194246Smarius    abort ();
1604194246Smarius
1605194246Smarius  /* If the outer context label has not been issued yet, we don't want
1606194246Smarius     to issue it as a part of this region, unless this is the
1607194246Smarius     correct region for the outer context. If we did, then the label for
1608194246Smarius     the outer context will be WITHIN the begin/end labels,
1609194246Smarius     and we could get an infinte loop when it tried to rethrow, or just
1610194246Smarius     generally incorrect execution following a throw. */
1611194246Smarius
1612194246Smarius  dont_issue = ((INSN_UID (node->entry->outer_context) == 0)
1613194246Smarius            && (ehstack.top->entry != node->entry));
1614223986Smarius
1615194246Smarius  ehstack.top->entry->outer_context = node->entry->outer_context;
1616194246Smarius
1617194246Smarius  /* Since we are rethrowing to the OUTER region, we know we don't need
1618194246Smarius     a jump around sequence for this region, so we'll pretend the outer
1619194246Smarius     context label has been issued by setting INSN_UID to 1, then clearing
1620194246Smarius     it again afterwards. */
1621194246Smarius
1622194246Smarius  if (dont_issue)
1623194246Smarius    INSN_UID (node->entry->outer_context) = 1;
1624194246Smarius
1625194246Smarius  /* Just rethrow.  size_zero_node is just a NOP.  */
1626194246Smarius  expand_eh_region_end (size_zero_node);
1627194246Smarius
1628194246Smarius  if (dont_issue)
1629223986Smarius    INSN_UID (node->entry->outer_context) = 0;
1630194246Smarius}
1631194246Smarius
1632194246Smarius/* If we are using the setjmp/longjmp EH codegen method, we emit a
1633194246Smarius   call to __sjthrow.
1634194246Smarius
1635194246Smarius   Otherwise, we emit a call to __throw and note that we threw
1636194246Smarius   something, so we know we need to generate the necessary code for
1637194246Smarius   __throw.
1638194246Smarius
1639194246Smarius   Before invoking throw, the __eh_pc variable must have been set up
1640194246Smarius   to contain the PC being thrown from. This address is used by
1641194246Smarius   __throw to determine which exception region (if any) is
1642194246Smarius   responsible for handling the exception.  */
1643194246Smarius
1644194246Smariusvoid
1645194246Smariusemit_throw ()
1646194246Smarius{
1647194246Smarius  if (exceptions_via_longjmp)
1648194246Smarius    {
1649194246Smarius      emit_library_call (sjthrow_libfunc, 0, VOIDmode, 0);
1650194246Smarius    }
1651194246Smarius  else
1652194246Smarius    {
1653194246Smarius#ifdef JUMP_TO_THROW
1654215721Smarius      emit_indirect_jump (throw_libfunc);
1655194246Smarius#else
1656194246Smarius      emit_library_call (throw_libfunc, 0, VOIDmode, 0);
1657194246Smarius#endif
1658194246Smarius    }
1659194246Smarius  emit_barrier ();
1660194246Smarius}
1661194246Smarius
1662194246Smarius/* Throw the current exception.  If appropriate, this is done by jumping
1663194246Smarius   to the next handler.  */
1664194246Smarius
1665194246Smariusvoid
1666194246Smariusexpand_internal_throw ()
1667194246Smarius{
1668194246Smarius  emit_throw ();
1669194246Smarius}
1670194246Smarius
1671194246Smarius/* Called from expand_exception_blocks and expand_end_catch_block to
1672194246Smarius   emit any pending handlers/cleanups queued from expand_eh_region_end.  */
1673194246Smarius
1674194246Smariusvoid
1675194246Smariusexpand_leftover_cleanups ()
1676194246Smarius{
1677194246Smarius  struct eh_entry *entry;
1678194246Smarius
1679194246Smarius  while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
1680194246Smarius    {
1681194246Smarius      rtx prev;
1682194246Smarius
1683194246Smarius      /* A leftover try block. Shouldn't be one here.  */
1684194246Smarius      if (entry->finalization == integer_zero_node)
1685194246Smarius	abort ();
1686194246Smarius
1687194246Smarius      /* Output the label for the start of the exception handler.  */
1688194246Smarius
1689194246Smarius      receive_exception_label (entry->exception_handler_label);
1690194246Smarius
1691194246Smarius      /* register a handler for this cleanup region */
1692194246Smarius      add_new_handler (
1693194246Smarius        find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)),
1694194246Smarius        get_new_handler (entry->exception_handler_label, NULL));
1695194246Smarius
1696194246Smarius      /* And now generate the insns for the handler.  */
1697194246Smarius      expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
1698194246Smarius
1699194246Smarius      prev = get_last_insn ();
1700194246Smarius      if (prev == NULL || GET_CODE (prev) != BARRIER)
1701194246Smarius	/* Emit code to throw to the outer context if we fall off
1702194246Smarius	   the end of the handler.  */
1703194246Smarius	expand_rethrow (entry->outer_context);
1704194246Smarius
1705194246Smarius      do_pending_stack_adjust ();
1706194246Smarius      free (entry);
1707194246Smarius    }
1708194246Smarius}
1709194246Smarius
1710194246Smarius/* Called at the start of a block of try statements.  */
1711194246Smariusvoid
1712194246Smariusexpand_start_try_stmts ()
1713194246Smarius{
1714194246Smarius  if (! doing_eh (1))
1715194246Smarius    return;
1716194246Smarius
1717194246Smarius  expand_eh_region_start ();
1718194246Smarius}
1719194246Smarius
1720194246Smarius/* Called to begin a catch clause. The parameter is the object which
1721194246Smarius   will be passed to the runtime type check routine. */
1722194246Smariusvoid
1723194246Smariusstart_catch_handler (rtime)
1724194246Smarius     tree rtime;
1725194246Smarius{
1726194246Smarius  rtx handler_label;
1727194246Smarius  int insn_region_num;
1728194246Smarius  int eh_region_entry;
1729243857Sglebius
1730194246Smarius  if (! doing_eh (1))
1731194246Smarius    return;
1732194246Smarius
1733194246Smarius  handler_label = catchstack.top->entry->exception_handler_label;
1734194973Smarius  insn_region_num = CODE_LABEL_NUMBER (handler_label);
1735194246Smarius  eh_region_entry = find_func_region (insn_region_num);
1736194246Smarius
1737194973Smarius  /* If we've already issued this label, pick a new one */
1738194246Smarius  if (catchstack.top->entry->label_used)
1739194973Smarius    handler_label = gen_exception_label ();
1740194973Smarius  else
1741194246Smarius    catchstack.top->entry->label_used = 1;
1742194973Smarius
1743194246Smarius  receive_exception_label (handler_label);
1744194246Smarius
1745194246Smarius  add_new_handler (eh_region_entry, get_new_handler (handler_label, rtime));
1746194246Smarius
1747194246Smarius  if (flag_new_exceptions && ! exceptions_via_longjmp)
1748194246Smarius    return;
1749194246Smarius
1750194246Smarius  /* Under the old mechanism, as well as setjmp/longjmp, we need to
1751194246Smarius     issue code to compare 'rtime' to the value in eh_info, via the
1752194246Smarius     matching function in eh_info. If its is false, we branch around
1753194246Smarius     the handler we are about to issue. */
1754194246Smarius
1755194246Smarius  if (rtime != NULL_TREE && rtime != CATCH_ALL_TYPE)
1756194246Smarius    {
1757223986Smarius      rtx call_rtx, rtime_address;
1758194246Smarius
1759223986Smarius      if (catchstack.top->entry->false_label != NULL_RTX)
1760194246Smarius        fatal ("Compiler Bug: Never issued previous false_label");
1761223951Smarius      catchstack.top->entry->false_label = gen_exception_label ();
1762194246Smarius
1763194246Smarius      rtime_address = expand_expr (rtime, NULL_RTX, Pmode, EXPAND_INITIALIZER);
1764194246Smarius#ifdef POINTERS_EXTEND_UNSIGNED
1765194246Smarius      rtime_address = convert_memory_address (Pmode, rtime_address);
1766194246Smarius#endif
1767194246Smarius      rtime_address = force_reg (Pmode, rtime_address);
1768194246Smarius
1769194246Smarius      /* Now issue the call, and branch around handler if needed */
1770194246Smarius      call_rtx = emit_library_call_value (eh_rtime_match_libfunc, NULL_RTX,
1771194246Smarius                                          0, SImode, 1, rtime_address, Pmode);
1772194246Smarius
1773194246Smarius      /* Did the function return true? */
1774243857Sglebius      emit_cmp_and_jump_insns (call_rtx, const0_rtx, EQ, NULL_RTX,
1775194246Smarius                               GET_MODE (call_rtx), 0, 0,
1776194246Smarius			       catchstack.top->entry->false_label);
1777194246Smarius    }
1778194246Smarius}
1779194246Smarius
1780194246Smarius/* Called to end a catch clause. If we aren't using the new exception
1781194973Smarius   model tabel mechanism, we need to issue the branch-around label
1782194246Smarius   for the end of the catch block. */
1783194973Smarius
1784194973Smariusvoid
1785194246Smariusend_catch_handler ()
1786194973Smarius{
1787194973Smarius  if (! doing_eh (1))
1788194973Smarius    return;
1789194973Smarius
1790194246Smarius  if (flag_new_exceptions && ! exceptions_via_longjmp)
1791194246Smarius    {
1792194246Smarius      emit_barrier ();
1793194246Smarius      return;
1794194246Smarius    }
1795194246Smarius
1796194246Smarius  /* A NULL label implies the catch clause was a catch all or cleanup */
1797208776Smarius  if (catchstack.top->entry->false_label == NULL_RTX)
1798194246Smarius    return;
1799194246Smarius
1800194246Smarius  emit_label (catchstack.top->entry->false_label);
1801194246Smarius  catchstack.top->entry->false_label = NULL_RTX;
1802194246Smarius}
1803194246Smarius
1804194246Smarius/* Generate RTL for the start of a group of catch clauses.
1805194246Smarius
1806194246Smarius   It is responsible for starting a new instruction sequence for the
1807194246Smarius   instructions in the catch block, and expanding the handlers for the
1808194246Smarius   internally-generated exception regions nested within the try block
1809194246Smarius   corresponding to this catch block.  */
1810208776Smarius
1811243857Sglebiusvoid
1812208776Smariusexpand_start_all_catch ()
1813208776Smarius{
1814208776Smarius  struct eh_entry *entry;
1815208776Smarius  tree label;
1816208776Smarius  rtx outer_context;
1817208776Smarius
1818208776Smarius  if (! doing_eh (1))
1819208776Smarius    return;
1820194973Smarius
1821208776Smarius  outer_context = ehstack.top->entry->outer_context;
1822208776Smarius
1823208776Smarius  /* End the try block.  */
1824208776Smarius  expand_eh_region_end (integer_zero_node);
1825208776Smarius
1826194973Smarius  emit_line_note (input_filename, lineno);
1827208776Smarius  label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
1828208776Smarius
1829208776Smarius  /* The label for the exception handling block that we will save.
1830208776Smarius     This is Lresume in the documentation.  */
1831208776Smarius  expand_label (label);
1832194246Smarius
1833208776Smarius  /* Push the label that points to where normal flow is resumed onto
1834208776Smarius     the top of the label stack.  */
1835208776Smarius  push_label_entry (&caught_return_label_stack, NULL_RTX, label);
1836208776Smarius
1837208776Smarius  /* Start a new sequence for all the catch blocks.  We will add this
1838194246Smarius     to the global sequence catch_clauses when we have completed all
1839194246Smarius     the handlers in this handler-seq.  */
1840194246Smarius  start_sequence ();
1841194246Smarius
1842208776Smarius  entry = dequeue_eh_entry (&ehqueue);
1843194246Smarius  for ( ; entry->finalization != integer_zero_node;
1844194246Smarius                                 entry = dequeue_eh_entry (&ehqueue))
1845194246Smarius    {
1846194246Smarius      rtx prev;
1847194246Smarius
1848194246Smarius      /* Emit the label for the cleanup handler for this region, and
1849194246Smarius	 expand the code for the handler.
1850194246Smarius
1851194246Smarius	 Note that a catch region is handled as a side-effect here;
1852194246Smarius	 for a try block, entry->finalization will contain
1853194246Smarius	 integer_zero_node, so no code will be generated in the
1854194246Smarius	 expand_expr call below. But, the label for the handler will
1855223986Smarius	 still be emitted, so any code emitted after this point will
1856194246Smarius	 end up being the handler.  */
1857223986Smarius
1858194246Smarius      receive_exception_label (entry->exception_handler_label);
1859223951Smarius
1860194246Smarius      /* register a handler for this cleanup region */
1861194246Smarius      add_new_handler (
1862194246Smarius        find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)),
1863194246Smarius        get_new_handler (entry->exception_handler_label, NULL));
1864194246Smarius
1865194246Smarius      /* And now generate the insns for the cleanup handler.  */
1866194246Smarius      expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
1867194246Smarius
1868194246Smarius      prev = get_last_insn ();
1869194246Smarius      if (prev == NULL || GET_CODE (prev) != BARRIER)
1870194246Smarius	/* Code to throw out to outer context when we fall off end
1871194246Smarius	   of the handler. We can't do this here for catch blocks,
1872194246Smarius	   so it's done in expand_end_all_catch instead.  */
1873194904Smarius	expand_rethrow (entry->outer_context);
1874194904Smarius
1875194246Smarius      do_pending_stack_adjust ();
1876194246Smarius      free (entry);
1877194246Smarius    }
1878194246Smarius
1879194246Smarius  /* At this point, all the cleanups are done, and the ehqueue now has
1880194246Smarius     the current exception region at its head. We dequeue it, and put it
1881194246Smarius     on the catch stack. */
1882194246Smarius
1883194246Smarius    push_entry (&catchstack, entry);
1884194246Smarius
1885215721Smarius  /* If we are not doing setjmp/longjmp EH, because we are reordered
1886194246Smarius     out of line, we arrange to rethrow in the outer context.  We need to
1887194246Smarius     do this because we are not physically within the region, if any, that
1888194246Smarius     logically contains this catch block.  */
1889194246Smarius  if (! exceptions_via_longjmp)
1890194246Smarius    {
1891194246Smarius      expand_eh_region_start ();
1892194246Smarius      ehstack.top->entry->outer_context = outer_context;
1893194246Smarius    }
1894194246Smarius
1895223986Smarius}
1896194246Smarius
1897194246Smarius/* Finish up the catch block.  At this point all the insns for the
1898194246Smarius   catch clauses have already been generated, so we only have to add
1899194246Smarius   them to the catch_clauses list. We also want to make sure that if
1900194246Smarius   we fall off the end of the catch clauses that we rethrow to the
1901194246Smarius   outer EH region.  */
1902194246Smarius
1903194246Smariusvoid
1904194246Smariusexpand_end_all_catch ()
1905194246Smarius{
1906194246Smarius  rtx new_catch_clause;
1907194246Smarius  struct eh_entry *entry;
1908194246Smarius
1909194246Smarius  if (! doing_eh (1))
1910194246Smarius    return;
1911194246Smarius
1912194246Smarius  /* Dequeue the current catch clause region. */
1913223986Smarius  entry = pop_eh_entry (&catchstack);
1914223986Smarius  free (entry);
1915194246Smarius
1916223986Smarius  if (! exceptions_via_longjmp)
1917223986Smarius    {
1918194246Smarius      rtx outer_context = ehstack.top->entry->outer_context;
1919194246Smarius
1920194246Smarius      /* Finish the rethrow region.  size_zero_node is just a NOP.  */
1921194246Smarius      expand_eh_region_end (size_zero_node);
1922194246Smarius      /* New exceptions handling models will never have a fall through
1923194246Smarius         of a catch clause */
1924223986Smarius      if (!flag_new_exceptions)
1925194246Smarius        expand_rethrow (outer_context);
1926194246Smarius    }
1927194246Smarius  else
1928194246Smarius    expand_rethrow (NULL_RTX);
1929194246Smarius
1930194246Smarius  /* Code to throw out to outer context, if we fall off end of catch
1931194246Smarius     handlers.  This is rethrow (Lresume, same id, same obj) in the
1932194246Smarius     documentation. We use Lresume because we know that it will throw
1933194246Smarius     to the correct context.
1934194246Smarius
1935194246Smarius     In other words, if the catch handler doesn't exit or return, we
1936194246Smarius     do a "throw" (using the address of Lresume as the point being
1937194246Smarius     thrown from) so that the outer EH region can then try to process
1938194246Smarius     the exception.  */
1939194246Smarius
1940194246Smarius  /* Now we have the complete catch sequence.  */
1941194246Smarius  new_catch_clause = get_insns ();
1942194246Smarius  end_sequence ();
1943194246Smarius
1944194246Smarius  /* This level of catch blocks is done, so set up the successful
1945194246Smarius     catch jump label for the next layer of catch blocks.  */
1946194246Smarius  pop_label_entry (&caught_return_label_stack);
1947194904Smarius  pop_label_entry (&outer_context_label_stack);
1948194246Smarius
1949223986Smarius  /* Add the new sequence of catches to the main one for this function.  */
1950194246Smarius  push_to_sequence (catch_clauses);
1951194904Smarius  emit_insns (new_catch_clause);
1952194904Smarius  catch_clauses = get_insns ();
1953194246Smarius  end_sequence ();
1954194246Smarius
1955194246Smarius  /* Here we fall through into the continuation code.  */
1956194246Smarius}
1957194246Smarius
1958194246Smarius/* Rethrow from the outer context LABEL.  */
1959194246Smarius
1960194246Smariusstatic void
1961194246Smariusexpand_rethrow (label)
1962194246Smarius     rtx label;
1963194246Smarius{
1964194246Smarius  if (exceptions_via_longjmp)
1965194904Smarius    emit_throw ();
1966223986Smarius  else
1967194904Smarius    if (flag_new_exceptions)
1968194904Smarius      {
1969194246Smarius        rtx insn, val;
1970194246Smarius        if (label == NULL_RTX)
1971194904Smarius          label = last_rethrow_symbol;
1972194246Smarius        emit_library_call (rethrow_libfunc, 0, VOIDmode, 1, label, Pmode);
1973194246Smarius        SYMBOL_REF_USED (label) = 1;
1974194246Smarius
1975194904Smarius	/* Search backwards for the actual call insn.  */
1976194904Smarius        insn = get_last_insn ();
1977194904Smarius	while (GET_CODE (insn) != CALL_INSN)
1978194904Smarius	  insn = PREV_INSN (insn);
1979194904Smarius	delete_insns_since (insn);
1980194904Smarius
1981194904Smarius        /* Mark the label/symbol on the call. */
1982194904Smarius        val = GEN_INT (eh_region_from_symbol (label));
1983194904Smarius        REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_RETHROW, val,
1984194904Smarius					      REG_NOTES (insn));
1985194904Smarius        emit_barrier ();
1986194904Smarius      }
1987194904Smarius    else
1988194904Smarius      emit_jump (label);
1989194904Smarius}
1990194904Smarius
1991194904Smarius/* End all the pending exception regions on protect_list. The handlers
1992194246Smarius   will be emitted when expand_leftover_cleanups is invoked.  */
1993194246Smarius
1994194904Smariusvoid
1995194904Smariusend_protect_partials ()
1996194904Smarius{
1997194904Smarius  while (protect_list)
1998194904Smarius    {
1999194246Smarius      expand_eh_region_end (TREE_VALUE (protect_list));
2000194246Smarius      protect_list = TREE_CHAIN (protect_list);
2001194904Smarius    }
2002194246Smarius}
2003223986Smarius
2004194246Smarius/* Arrange for __terminate to be called if there is an unhandled throw
2005194246Smarius   from within E.  */
2006194246Smarius
2007215721Smariustree
2008194246Smariusprotect_with_terminate (e)
2009194246Smarius     tree e;
2010194246Smarius{
2011194246Smarius  /* We only need to do this when using setjmp/longjmp EH and the
2012194246Smarius     language requires it, as otherwise we protect all of the handlers
2013194246Smarius     at once, if we need to.  */
2014194246Smarius  if (exceptions_via_longjmp && protect_cleanup_actions_with_terminate)
2015194246Smarius    {
2016194246Smarius      tree handler, result;
2017194246Smarius
2018194246Smarius      /* All cleanups must be on the function_obstack.  */
2019194246Smarius      push_obstacks_nochange ();
2020194246Smarius      resume_temporary_allocation ();
2021194246Smarius
2022194246Smarius      handler = make_node (RTL_EXPR);
2023194246Smarius      TREE_TYPE (handler) = void_type_node;
2024194246Smarius      RTL_EXPR_RTL (handler) = const0_rtx;
2025194246Smarius      TREE_SIDE_EFFECTS (handler) = 1;
2026194246Smarius      start_sequence_for_rtl_expr (handler);
2027194246Smarius
2028194246Smarius      emit_library_call (terminate_libfunc, 0, VOIDmode, 0);
2029194246Smarius      emit_barrier ();
2030194246Smarius
2031194246Smarius      RTL_EXPR_SEQUENCE (handler) = get_insns ();
2032194246Smarius      end_sequence ();
2033194246Smarius
2034194246Smarius      result = build (TRY_CATCH_EXPR, TREE_TYPE (e), e, handler);
2035194246Smarius      TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (e);
2036194246Smarius      TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
2037194246Smarius      TREE_READONLY (result) = TREE_READONLY (e);
2038194246Smarius
2039194246Smarius      pop_obstacks ();
2040194246Smarius
2041194246Smarius      e = result;
2042194246Smarius    }
2043223986Smarius
2044194246Smarius  return e;
2045194246Smarius}
2046194246Smarius
2047194246Smarius/* The exception table that we build that is used for looking up and
2048194246Smarius   dispatching exceptions, the current number of entries, and its
2049194246Smarius   maximum size before we have to extend it.
2050194246Smarius
2051223986Smarius   The number in eh_table is the code label number of the exception
2052194246Smarius   handler for the region. This is added by add_eh_table_entry and
2053194246Smarius   used by output_exception_table_entry.  */
2054194246Smarius
2055194246Smariusstatic int *eh_table = NULL;
2056194246Smariusstatic int eh_table_size = 0;
2057194246Smariusstatic int eh_table_max_size = 0;
2058194246Smarius
2059194246Smarius/* Note the need for an exception table entry for region N.  If we
2060223986Smarius   don't need to output an explicit exception table, avoid all of the
2061194246Smarius   extra work.
2062194246Smarius
2063194246Smarius   Called from final_scan_insn when a NOTE_INSN_EH_REGION_BEG is seen.
2064194246Smarius   (Or NOTE_INSN_EH_REGION_END sometimes)
2065194246Smarius   N is the NOTE_BLOCK_NUMBER of the note, which comes from the code
2066194246Smarius   label number of the exception handler for the region.  */
2067194246Smarius
2068194246Smariusvoid
2069194246Smariusadd_eh_table_entry (n)
2070194904Smarius     int n;
2071194246Smarius{
2072194246Smarius#ifndef OMIT_EH_TABLE
2073194246Smarius  if (eh_table_size >= eh_table_max_size)
2074194246Smarius    {
2075194246Smarius      if (eh_table)
2076194904Smarius	{
2077194246Smarius	  eh_table_max_size += eh_table_max_size>>1;
2078194246Smarius
2079194246Smarius	  if (eh_table_max_size < 0)
2080223986Smarius	    abort ();
2081194246Smarius
2082223986Smarius	  eh_table = (int *) xrealloc (eh_table,
2083223986Smarius				       eh_table_max_size * sizeof (int));
2084194904Smarius	}
2085194904Smarius      else
2086223986Smarius	{
2087194904Smarius	  eh_table_max_size = 252;
2088223986Smarius	  eh_table = (int *) xmalloc (eh_table_max_size * sizeof (int));
2089194904Smarius	}
2090194904Smarius    }
2091194904Smarius  eh_table[eh_table_size++] = n;
2092194904Smarius#endif
2093194904Smarius}
2094194904Smarius
2095194904Smarius/* Return a non-zero value if we need to output an exception table.
2096194904Smarius
2097194904Smarius   On some platforms, we don't have to output a table explicitly.
2098194904Smarius   This routine doesn't mean we don't have one.  */
2099194904Smarius
2100194904Smariusint
2101194904Smariusexception_table_p ()
2102194904Smarius{
2103194904Smarius  if (eh_table)
2104194904Smarius    return 1;
2105194904Smarius
2106194904Smarius  return 0;
2107194904Smarius}
2108194246Smarius
2109194246Smarius/* Output the entry of the exception table corresponding to the
2110194904Smarius   exception region numbered N to file FILE.
2111194246Smarius
2112194246Smarius   N is the code label number corresponding to the handler of the
2113194246Smarius   region.  */
2114194246Smarius
2115194246Smariusstatic void
2116194246Smariusoutput_exception_table_entry (file, n)
2117194246Smarius     FILE *file;
2118194246Smarius     int n;
2119215721Smarius{
2120215721Smarius  char buf[256];
2121194246Smarius  rtx sym;
2122215721Smarius  struct handler_info *handler = get_first_handler (n);
2123194246Smarius  int index = find_func_region (n);
2124215721Smarius  rtx rethrow;
2125215721Smarius
2126194246Smarius /* form and emit the rethrow label, if needed  */
2127215721Smarius  rethrow = function_eh_regions[index].rethrow_label;
2128194246Smarius  if (rethrow != NULL_RTX && !flag_new_exceptions)
2129194246Smarius      rethrow = NULL_RTX;
2130194246Smarius  if (rethrow != NULL_RTX && handler == NULL)
2131194904Smarius    if (! SYMBOL_REF_USED (rethrow))
2132194246Smarius      rethrow = NULL_RTX;
2133194246Smarius
2134194246Smarius
2135194246Smarius  for ( ; handler != NULL || rethrow != NULL_RTX; handler = handler->next)
2136194246Smarius    {
2137194246Smarius      /* rethrow label should indicate the LAST entry for a region */
2138194246Smarius      if (rethrow != NULL_RTX && (handler == NULL || handler->next == NULL))
2139194246Smarius        {
2140194904Smarius          ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", n);
2141194246Smarius          assemble_label(buf);
2142194904Smarius          rethrow = NULL_RTX;
2143194904Smarius        }
2144194246Smarius
2145194246Smarius      ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
2146194246Smarius      sym = gen_rtx_SYMBOL_REF (Pmode, buf);
2147194246Smarius      assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
2148194246Smarius
2149194246Smarius      ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
2150194246Smarius      sym = gen_rtx_SYMBOL_REF (Pmode, buf);
2151194246Smarius      assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
2152194246Smarius
2153207585Smarius      if (handler == NULL)
2154207585Smarius        assemble_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1);
2155194246Smarius      else
2156194246Smarius        {
2157194246Smarius          ASM_GENERATE_INTERNAL_LABEL (buf, "L", handler->handler_number);
2158194246Smarius          sym = gen_rtx_SYMBOL_REF (Pmode, buf);
2159194246Smarius          assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
2160194246Smarius        }
2161194246Smarius
2162194246Smarius      if (flag_new_exceptions)
2163194246Smarius        {
2164194246Smarius          if (handler == NULL || handler->type_info == NULL)
2165194246Smarius            assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
2166194246Smarius          else
2167194246Smarius            if (handler->type_info == CATCH_ALL_TYPE)
2168194246Smarius              assemble_integer (GEN_INT (CATCH_ALL_TYPE),
2169194246Smarius                                             POINTER_SIZE / BITS_PER_UNIT, 1);
2170194246Smarius            else
2171194246Smarius              output_constant ((tree)(handler->type_info),
2172194246Smarius                                                POINTER_SIZE / BITS_PER_UNIT);
2173194246Smarius        }
2174194246Smarius      putc ('\n', file);		/* blank line */
2175194246Smarius      /* We only output the first label under the old scheme */
2176194246Smarius      if (! flag_new_exceptions || handler == NULL)
2177194246Smarius        break;
2178194246Smarius    }
2179194246Smarius}
2180194246Smarius
2181194246Smarius/* Output the exception table if we have and need one.  */
2182194246Smarius
2183194246Smariusstatic short language_code = 0;
2184194246Smariusstatic short version_code = 0;
2185194246Smarius
2186194246Smarius/* This routine will set the language code for exceptions. */
2187194246Smariusvoid
2188194246Smariusset_exception_lang_code (code)
2189194246Smarius     int code;
2190194246Smarius{
2191194246Smarius  language_code = code;
2192194246Smarius}
2193194246Smarius
2194194246Smarius/* This routine will set the language version code for exceptions. */
2195194246Smariusvoid
2196194246Smariusset_exception_version_code (code)
2197194246Smarius     int code;
2198194246Smarius{
2199194246Smarius  version_code = code;
2200194246Smarius}
2201194246Smarius
2202194246Smarius
2203194246Smariusvoid
2204194246Smariusoutput_exception_table ()
2205194246Smarius{
2206194246Smarius  int i;
2207194246Smarius  char buf[256];
2208194246Smarius  extern FILE *asm_out_file;
2209194246Smarius
2210194246Smarius  if (! doing_eh (0) || ! eh_table)
2211194246Smarius    return;
2212194246Smarius
2213194246Smarius  exception_section ();
2214194246Smarius
2215194246Smarius  /* Beginning marker for table.  */
2216194246Smarius  assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
2217194246Smarius  assemble_label ("__EXCEPTION_TABLE__");
2218194246Smarius
2219194246Smarius  if (flag_new_exceptions)
2220194246Smarius    {
2221194246Smarius      assemble_integer (GEN_INT (NEW_EH_RUNTIME),
2222194246Smarius                                        POINTER_SIZE / BITS_PER_UNIT, 1);
2223194246Smarius      assemble_integer (GEN_INT (language_code), 2 , 1);
2224194246Smarius      assemble_integer (GEN_INT (version_code), 2 , 1);
2225194246Smarius
2226194246Smarius      /* Add enough padding to make sure table aligns on a pointer boundry. */
2227194246Smarius      i = GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT - 4;
2228194246Smarius      for ( ; i < 0; i = i + GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT)
2229194246Smarius        ;
2230194246Smarius      if (i != 0)
2231194246Smarius        assemble_integer (const0_rtx, i , 1);
2232194246Smarius
2233194246Smarius      /* Generate the label for offset calculations on rethrows */
2234194246Smarius      ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", 0);
2235194246Smarius      assemble_label(buf);
2236194246Smarius    }
2237194246Smarius
2238194246Smarius  for (i = 0; i < eh_table_size; ++i)
2239194246Smarius    output_exception_table_entry (asm_out_file, eh_table[i]);
2240194246Smarius
2241194246Smarius  free (eh_table);
2242194246Smarius  clear_function_eh_region ();
2243194246Smarius
2244194246Smarius  /* Ending marker for table.  */
2245194246Smarius  /* Generate the label for end of table. */
2246194246Smarius  ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", CODE_LABEL_NUMBER (final_rethrow));
2247194246Smarius  assemble_label(buf);
2248194246Smarius  assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
2249194246Smarius
2250194246Smarius  /* for binary compatability, the old __throw checked the second
2251194246Smarius     position for a -1, so we should output at least 2 -1's */
2252194246Smarius  if (! flag_new_exceptions)
2253194246Smarius    assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
2254194246Smarius
2255194246Smarius  putc ('\n', asm_out_file);		/* blank line */
2256194246Smarius}
2257194246Smarius
2258194246Smarius/* Emit code to get EH context.
2259194246Smarius
2260194246Smarius   We have to scan thru the code to find possible EH context registers.
2261194246Smarius   Inlined functions may use it too, and thus we'll have to be able
2262194246Smarius   to change them too.
2263207585Smarius
2264207585Smarius   This is done only if using exceptions_via_longjmp. */
2265194246Smarius
2266194246Smariusvoid
2267207585Smariusemit_eh_context ()
2268207585Smarius{
2269194246Smarius  rtx insn;
2270194246Smarius  rtx ehc = 0;
2271207585Smarius
2272207585Smarius  if (! doing_eh (0))
2273194246Smarius    return;
2274194246Smarius
2275194246Smarius  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
2276194246Smarius    if (GET_CODE (insn) == INSN
2277194246Smarius	&& GET_CODE (PATTERN (insn)) == USE)
2278194246Smarius      {
2279194246Smarius	rtx reg = find_reg_note (insn, REG_EH_CONTEXT, 0);
2280194246Smarius	if (reg)
2281194246Smarius	  {
2282194246Smarius	    rtx insns;
2283207585Smarius
2284207585Smarius	    start_sequence ();
2285194246Smarius
2286194246Smarius	    /* If this is the first use insn, emit the call here.  This
2287194246Smarius	       will always be at the top of our function, because if
2288194246Smarius	       expand_inline_function notices a REG_EH_CONTEXT note, it
2289194246Smarius	       adds a use insn to this function as well.  */
2290194246Smarius	    if (ehc == 0)
2291194246Smarius	      ehc = call_get_eh_context ();
2292194246Smarius
2293194246Smarius	    emit_move_insn (XEXP (reg, 0), ehc);
2294194246Smarius	    insns = get_insns ();
2295194246Smarius	    end_sequence ();
2296194246Smarius
2297194246Smarius	    emit_insns_before (insns, insn);
2298194246Smarius
2299194246Smarius            /* At -O0, we must make the context register stay alive so
2300194246Smarius               that the stupid.c register allocator doesn't get confused. */
2301194246Smarius            if (obey_regdecls != 0)
2302194246Smarius              {
2303194246Smarius                insns = gen_rtx_USE (GET_MODE (XEXP (reg,0)), XEXP (reg,0));
2304194246Smarius                emit_insn_before (insns, get_last_insn ());
2305194246Smarius              }
2306194246Smarius	  }
2307194246Smarius      }
2308194246Smarius}
2309194246Smarius
2310194246Smarius/* Scan the current insns and build a list of handler labels. The
2311194246Smarius   resulting list is placed in the global variable exception_handler_labels.
2312194246Smarius
2313194246Smarius   It is called after the last exception handling region is added to
2314194246Smarius   the current function (when the rtl is almost all built for the
2315194246Smarius   current function) and before the jump optimization pass.  */
2316194246Smarius
2317194246Smariusvoid
2318194246Smariusfind_exception_handler_labels ()
2319194246Smarius{
2320194246Smarius  rtx insn;
2321194246Smarius
2322194246Smarius  exception_handler_labels = NULL_RTX;
2323213893Smarius
2324194246Smarius  /* If we aren't doing exception handling, there isn't much to check.  */
2325194246Smarius  if (! doing_eh (0))
2326194246Smarius    return;
2327194246Smarius
2328194246Smarius  /* For each start of a region, add its label to the list.  */
2329194246Smarius
2330194246Smarius  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
2331194246Smarius    {
2332194246Smarius      struct handler_info* ptr;
2333194246Smarius      if (GET_CODE (insn) == NOTE
2334194246Smarius	  && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
2335194246Smarius	{
2336194246Smarius          ptr = get_first_handler (NOTE_BLOCK_NUMBER (insn));
2337194246Smarius          for ( ; ptr; ptr = ptr->next)
2338194246Smarius            {
2339194246Smarius              /* make sure label isn't in the list already */
2340194246Smarius              rtx x;
2341194246Smarius              for (x = exception_handler_labels; x; x = XEXP (x, 1))
2342194246Smarius                if (XEXP (x, 0) == ptr->handler_label)
2343194246Smarius                  break;
2344194246Smarius              if (! x)
2345194246Smarius                exception_handler_labels = gen_rtx_EXPR_LIST (VOIDmode,
2346194246Smarius                               ptr->handler_label, exception_handler_labels);
2347194246Smarius            }
2348194246Smarius	}
2349194246Smarius    }
2350223951Smarius}
2351223951Smarius
2352194246Smarius/* Return a value of 1 if the parameter label number is an exception handler
2353194246Smarius   label. Return 0 otherwise. */
2354194246Smarius
2355194246Smariusint
2356194246Smariusis_exception_handler_label (lab)
2357194246Smarius     int lab;
2358194246Smarius{
2359194246Smarius  rtx x;
2360223951Smarius  for (x = exception_handler_labels ; x ; x = XEXP (x, 1))
2361194246Smarius    if (lab == CODE_LABEL_NUMBER (XEXP (x, 0)))
2362223951Smarius      return 1;
2363194246Smarius  return 0;
2364194246Smarius}
2365194246Smarius
2366194246Smarius/* Perform sanity checking on the exception_handler_labels list.
2367194246Smarius
2368194246Smarius   Can be called after find_exception_handler_labels is called to
2369194246Smarius   build the list of exception handlers for the current function and
2370194246Smarius   before we finish processing the current function.  */
2371194246Smarius
2372194246Smariusvoid
2373194246Smariuscheck_exception_handler_labels ()
2374194246Smarius{
2375194246Smarius  rtx insn, insn2;
2376194246Smarius
2377194246Smarius  /* If we aren't doing exception handling, there isn't much to check.  */
2378194246Smarius  if (! doing_eh (0))
2379194246Smarius    return;
2380194246Smarius
2381194246Smarius  /* Make sure there is no more than 1 copy of a label */
2382194246Smarius  for (insn = exception_handler_labels; insn; insn = XEXP (insn, 1))
2383194246Smarius    {
2384194246Smarius      int count = 0;
2385194246Smarius      for (insn2 = exception_handler_labels; insn2; insn2 = XEXP (insn2, 1))
2386194246Smarius        if (XEXP (insn, 0) == XEXP (insn2, 0))
2387194246Smarius          count++;
2388194246Smarius      if (count != 1)
2389194246Smarius       warning ("Counted %d copies of EH region %d in list.\n", count,
2390194246Smarius                                        CODE_LABEL_NUMBER (insn));
2391194246Smarius    }
2392194246Smarius
2393194246Smarius}
2394194246Smarius
2395194246Smarius/* This group of functions initializes the exception handling data
2396194246Smarius   structures at the start of the compilation, initializes the data
2397194246Smarius   structures at the start of a function, and saves and restores the
2398194246Smarius   exception handling data structures for the start/end of a nested
2399194246Smarius   function.  */
2400194246Smarius
2401194246Smarius/* Toplevel initialization for EH things.  */
2402194246Smarius
2403194246Smariusvoid
2404194246Smariusinit_eh ()
2405194246Smarius{
2406194246Smarius  first_rethrow_symbol = create_rethrow_ref (0);
2407194246Smarius  final_rethrow = gen_exception_label ();
2408194246Smarius  last_rethrow_symbol = create_rethrow_ref (CODE_LABEL_NUMBER (final_rethrow));
2409194246Smarius}
2410194246Smarius
2411194246Smarius/* Initialize the per-function EH information.  */
2412194246Smarius
2413194246Smariusvoid
2414194246Smariusinit_eh_for_function ()
2415194246Smarius{
2416194246Smarius  ehstack.top = 0;
2417194246Smarius  catchstack.top = 0;
2418194246Smarius  ehqueue.head = ehqueue.tail = 0;
2419194246Smarius  catch_clauses = NULL_RTX;
2420223951Smarius  false_label_stack = 0;
2421223986Smarius  caught_return_label_stack = 0;
2422194246Smarius  protect_list = NULL_TREE;
2423194246Smarius  current_function_ehc = NULL_RTX;
2424194246Smarius  eh_return_context = NULL_RTX;
2425194246Smarius  eh_return_stack_adjust = NULL_RTX;
2426194246Smarius  eh_return_handler = NULL_RTX;
2427194246Smarius  eh_return_stub_label = NULL_RTX;
2428194246Smarius}
2429194246Smarius
2430194246Smarius/* Save some of the per-function EH info into the save area denoted by
2431194246Smarius   P.
2432194246Smarius
2433194246Smarius   This is currently called from save_stmt_status.  */
2434194246Smarius
2435194246Smariusvoid
2436194246Smariussave_eh_status (p)
2437194246Smarius     struct function *p;
2438194246Smarius{
2439194246Smarius  if (p == NULL)
2440194246Smarius    abort ();
2441194246Smarius
2442194246Smarius  p->ehstack = ehstack;
2443194246Smarius  p->catchstack = catchstack;
2444194246Smarius  p->ehqueue = ehqueue;
2445194246Smarius  p->catch_clauses = catch_clauses;
2446194246Smarius  p->false_label_stack = false_label_stack;
2447194246Smarius  p->caught_return_label_stack = caught_return_label_stack;
2448194246Smarius  p->protect_list = protect_list;
2449194246Smarius  p->ehc = current_function_ehc;
2450194246Smarius  p->eh_return_stub_label = eh_return_stub_label;
2451194246Smarius
2452194246Smarius  init_eh_for_function ();
2453194246Smarius}
2454194246Smarius
2455194246Smarius/* Restore the per-function EH info saved into the area denoted by P.
2456194246Smarius
2457194246Smarius   This is currently called from restore_stmt_status.  */
2458194246Smarius
2459194246Smariusvoid
2460194246Smariusrestore_eh_status (p)
2461194246Smarius     struct function *p;
2462194246Smarius{
2463194246Smarius  if (p == NULL)
2464194246Smarius    abort ();
2465194246Smarius
2466194246Smarius  protect_list = p->protect_list;
2467194246Smarius  caught_return_label_stack = p->caught_return_label_stack;
2468194246Smarius  false_label_stack = p->false_label_stack;
2469194246Smarius  catch_clauses	= p->catch_clauses;
2470194246Smarius  ehqueue = p->ehqueue;
2471194246Smarius  ehstack = p->ehstack;
2472194246Smarius  catchstack = p->catchstack;
2473194246Smarius  current_function_ehc = p->ehc;
2474194246Smarius  eh_return_stub_label = p->eh_return_stub_label;
2475194246Smarius}
2476194246Smarius
2477194246Smarius/* This section is for the exception handling specific optimization
2478194246Smarius   pass.  First are the internal routines, and then the main
2479194246Smarius   optimization pass.  */
2480194246Smarius
2481194246Smarius/* Determine if the given INSN can throw an exception.  */
2482194246Smarius
2483194246Smariusstatic int
2484194246Smariuscan_throw (insn)
2485194246Smarius     rtx insn;
2486194246Smarius{
2487194246Smarius  /* Calls can always potentially throw exceptions.  */
2488194246Smarius  if (GET_CODE (insn) == CALL_INSN)
2489194246Smarius    return 1;
2490194246Smarius
2491194246Smarius  if (asynchronous_exceptions)
2492194246Smarius    {
2493194246Smarius      /* If we wanted asynchronous exceptions, then everything but NOTEs
2494194246Smarius	 and CODE_LABELs could throw.  */
2495194246Smarius      if (GET_CODE (insn) != NOTE && GET_CODE (insn) != CODE_LABEL)
2496194246Smarius	return 1;
2497194246Smarius    }
2498194246Smarius
2499194246Smarius  return 0;
2500194246Smarius}
2501194904Smarius
2502194904Smarius/* Scan a exception region looking for the matching end and then
2503194246Smarius   remove it if possible. INSN is the start of the region, N is the
2504194246Smarius   region number, and DELETE_OUTER is to note if anything in this
2505194246Smarius   region can throw.
2506194246Smarius
2507194246Smarius   Regions are removed if they cannot possibly catch an exception.
2508194246Smarius   This is determined by invoking can_throw on each insn within the
2509194246Smarius   region; if can_throw returns true for any of the instructions, the
2510194246Smarius   region can catch an exception, since there is an insn within the
2511194246Smarius   region that is capable of throwing an exception.
2512194246Smarius
2513194246Smarius   Returns the NOTE_INSN_EH_REGION_END corresponding to this region, or
2514194246Smarius   calls abort if it can't find one.
2515194246Smarius
2516194246Smarius   Can abort if INSN is not a NOTE_INSN_EH_REGION_BEGIN, or if N doesn't
2517194246Smarius   correspond to the region number, or if DELETE_OUTER is NULL.  */
2518194246Smarius
2519194246Smariusstatic rtx
2520194246Smariusscan_region (insn, n, delete_outer)
2521194246Smarius     rtx insn;
2522194246Smarius     int n;
2523194246Smarius     int *delete_outer;
2524194246Smarius{
2525194246Smarius  rtx start = insn;
2526194246Smarius
2527194246Smarius  /* Assume we can delete the region.  */
2528194246Smarius  int delete = 1;
2529194246Smarius
2530194246Smarius  int r = find_func_region (n);
2531194246Smarius  /* Can't delete something which is rethrown to. */
2532194246Smarius  if (SYMBOL_REF_USED((function_eh_regions[r].rethrow_label)))
2533194246Smarius    delete = 0;
2534194246Smarius
2535194246Smarius  if (insn == NULL_RTX
2536223951Smarius      || GET_CODE (insn) != NOTE
2537223951Smarius      || NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
2538194246Smarius      || NOTE_BLOCK_NUMBER (insn) != n
2539223951Smarius      || delete_outer == NULL)
2540223951Smarius    abort ();
2541194246Smarius
2542194246Smarius  insn = NEXT_INSN (insn);
2543194246Smarius
2544223951Smarius  /* Look for the matching end.  */
2545223951Smarius  while (! (GET_CODE (insn) == NOTE
2546223951Smarius	    && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
2547223951Smarius    {
2548194246Smarius      /* If anything can throw, we can't remove the region.  */
2549223951Smarius      if (delete && can_throw (insn))
2550194246Smarius	{
2551194246Smarius	  delete = 0;
2552194246Smarius	}
2553194246Smarius
2554194246Smarius      /* Watch out for and handle nested regions.  */
2555194246Smarius      if (GET_CODE (insn) == NOTE
2556194246Smarius	  && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
2557194246Smarius	{
2558194246Smarius	  insn = scan_region (insn, NOTE_BLOCK_NUMBER (insn), &delete);
2559194246Smarius	}
2560194246Smarius
2561194246Smarius      insn = NEXT_INSN (insn);
2562194246Smarius    }
2563194246Smarius
2564194246Smarius  /* The _BEG/_END NOTEs must match and nest.  */
2565194246Smarius  if (NOTE_BLOCK_NUMBER (insn) != n)
2566194246Smarius    abort ();
2567194246Smarius
2568194246Smarius  /* If anything in this exception region can throw, we can throw.  */
2569194246Smarius  if (! delete)
2570194246Smarius    *delete_outer = 0;
2571195049Srwatson  else
2572194246Smarius    {
2573194246Smarius      /* Delete the start and end of the region.  */
2574194246Smarius      delete_insn (start);
2575194246Smarius      delete_insn (insn);
2576194246Smarius
2577194246Smarius/* We no longer removed labels here, since flow will now remove any
2578194246Smarius   handler which cannot be called any more. */
2579194246Smarius
2580194246Smarius#if 0
2581194246Smarius      /* Only do this part if we have built the exception handler
2582194246Smarius         labels.  */
2583194246Smarius      if (exception_handler_labels)
2584195049Srwatson	{
2585194246Smarius	  rtx x, *prev = &exception_handler_labels;
2586194246Smarius
2587194246Smarius	  /* Find it in the list of handlers.  */
2588194246Smarius	  for (x = exception_handler_labels; x; x = XEXP (x, 1))
2589194246Smarius	    {
2590194246Smarius	      rtx label = XEXP (x, 0);
2591194246Smarius	      if (CODE_LABEL_NUMBER (label) == n)
2592194246Smarius		{
2593194246Smarius		  /* If we are the last reference to the handler,
2594194246Smarius                     delete it.  */
2595223951Smarius		  if (--LABEL_NUSES (label) == 0)
2596223951Smarius		    delete_insn (label);
2597194246Smarius
2598194246Smarius		  if (optimize)
2599194246Smarius		    {
2600194246Smarius		      /* Remove it from the list of exception handler
2601194246Smarius			 labels, if we are optimizing.  If we are not, then
2602194246Smarius			 leave it in the list, as we are not really going to
2603194246Smarius			 remove the region.  */
2604194246Smarius		      *prev = XEXP (x, 1);
2605194246Smarius		      XEXP (x, 1) = 0;
2606194246Smarius		      XEXP (x, 0) = 0;
2607194246Smarius		    }
2608194246Smarius
2609194246Smarius		  break;
2610194246Smarius		}
2611194246Smarius	      prev = &XEXP (x, 1);
2612194246Smarius	    }
2613194246Smarius	}
2614194246Smarius#endif
2615194246Smarius    }
2616194246Smarius  return insn;
2617194246Smarius}
2618194246Smarius
2619194246Smarius/* Perform various interesting optimizations for exception handling
2620227843Smarius   code.
2621194246Smarius
2622194246Smarius   We look for empty exception regions and make them go (away). The
2623194246Smarius   jump optimization code will remove the handler if nothing else uses
2624194246Smarius   it.  */
2625194246Smarius
2626194246Smariusvoid
2627194246Smariusexception_optimize ()
2628194246Smarius{
2629194246Smarius  rtx insn;
2630194246Smarius  int n;
2631194246Smarius
2632194246Smarius  /* Remove empty regions.  */
2633194246Smarius  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
2634194246Smarius    {
2635194246Smarius      if (GET_CODE (insn) == NOTE
2636194246Smarius	  && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
2637194246Smarius	{
2638242625Sdim	  /* Since scan_region will return the NOTE_INSN_EH_REGION_END
2639194246Smarius	     insn, we will indirectly skip through all the insns
2640194246Smarius	     inbetween. We are also guaranteed that the value of insn
2641194246Smarius	     returned will be valid, as otherwise scan_region won't
2642194246Smarius	     return.  */
2643194246Smarius	  insn = scan_region (insn, NOTE_BLOCK_NUMBER (insn), &n);
2644194246Smarius	}
2645194246Smarius    }
2646194246Smarius}
2647194246Smarius
2648194246Smarius/* Various hooks for the DWARF 2 __throw routine.  */
2649194246Smarius
2650194246Smarius/* Do any necessary initialization to access arbitrary stack frames.
2651194246Smarius   On the SPARC, this means flushing the register windows.  */
2652194246Smarius
2653194246Smariusvoid
2654194246Smariusexpand_builtin_unwind_init ()
2655194246Smarius{
2656194246Smarius  /* Set this so all the registers get saved in our frame; we need to be
2657194246Smarius     able to copy the saved values for any registers from frames we unwind. */
2658194246Smarius  current_function_has_nonlocal_label = 1;
2659194246Smarius
2660194246Smarius#ifdef SETUP_FRAME_ADDRESSES
2661194246Smarius  SETUP_FRAME_ADDRESSES ();
2662194246Smarius#endif
2663194246Smarius}
2664194246Smarius
2665194246Smarius/* Given a value extracted from the return address register or stack slot,
2666194246Smarius   return the actual address encoded in that value.  */
2667207585Smarius
2668207585Smariusrtx
2669207585Smariusexpand_builtin_extract_return_addr (addr_tree)
2670207585Smarius     tree addr_tree;
2671207585Smarius{
2672194246Smarius  rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
2673194246Smarius  return eh_outer_context (addr);
2674194246Smarius}
2675207585Smarius
2676194246Smarius/* Given an actual address in addr_tree, do any necessary encoding
2677194246Smarius   and return the value to be stored in the return address register or
2678194246Smarius   stack slot so the epilogue will return to that address.  */
2679194246Smarius
2680207585Smariusrtx
2681194246Smariusexpand_builtin_frob_return_addr (addr_tree)
2682194246Smarius     tree addr_tree;
2683194246Smarius{
2684194246Smarius  rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
2685194246Smarius#ifdef RETURN_ADDR_OFFSET
2686194246Smarius  addr = plus_constant (addr, -RETURN_ADDR_OFFSET);
2687194246Smarius#endif
2688194246Smarius  return addr;
2689194246Smarius}
2690194246Smarius
2691194246Smarius/* Choose three registers for communication between the main body of
2692194246Smarius   __throw and the epilogue (or eh stub) and the exception handler.
2693194246Smarius   We must do this with hard registers because the epilogue itself
2694194246Smarius   will be generated after reload, at which point we may not reference
2695194246Smarius   pseudos at all.
2696194246Smarius
2697247579Smarius   The first passes the exception context to the handler.  For this
2698247579Smarius   we use the return value register for a void*.
2699247579Smarius
2700247579Smarius   The second holds the stack pointer value to be restored.  For
2701194246Smarius   this we use the static chain register if it exists and is different
2702194246Smarius   from the previous, otherwise some arbitrary call-clobbered register.
2703194246Smarius
2704194246Smarius   The third holds the address of the handler itself.  Here we use
2705194246Smarius   some arbitrary call-clobbered register.  */
2706194246Smarius
2707194246Smariusstatic void
2708194246Smariuseh_regs (pcontext, psp, pra, outgoing)
2709194246Smarius     rtx *pcontext, *psp, *pra;
2710194246Smarius     int outgoing;
2711194246Smarius{
2712194246Smarius  rtx rcontext, rsp, rra;
2713194246Smarius  int i;
2714194246Smarius
2715194246Smarius#ifdef FUNCTION_OUTGOING_VALUE
2716194246Smarius  if (outgoing)
2717194246Smarius    rcontext = FUNCTION_OUTGOING_VALUE (build_pointer_type (void_type_node),
2718194246Smarius				        current_function_decl);
2719194246Smarius  else
2720194246Smarius#endif
2721194246Smarius    rcontext = FUNCTION_VALUE (build_pointer_type (void_type_node),
2722194246Smarius			       current_function_decl);
2723194246Smarius
2724207585Smarius#ifdef STATIC_CHAIN_REGNUM
2725207585Smarius  if (outgoing)
2726207585Smarius    rsp = static_chain_incoming_rtx;
2727207585Smarius  else
2728207585Smarius    rsp = static_chain_rtx;
2729207585Smarius  if (REGNO (rsp) == REGNO (rcontext))
2730207585Smarius#endif /* STATIC_CHAIN_REGNUM */
2731194246Smarius    rsp = NULL_RTX;
2732194246Smarius
2733207585Smarius  if (rsp == NULL_RTX)
2734207585Smarius    {
2735207585Smarius      for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
2736207585Smarius	if (call_used_regs[i] && ! fixed_regs[i] && i != REGNO (rcontext))
2737207585Smarius	  break;
2738194246Smarius      if (i == FIRST_PSEUDO_REGISTER)
2739194246Smarius	abort();
2740194246Smarius
2741194246Smarius      rsp = gen_rtx_REG (Pmode, i);
2742194246Smarius    }
2743194246Smarius
2744194246Smarius  for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
2745194246Smarius    if (call_used_regs[i] && ! fixed_regs[i]
2746194246Smarius	&& i != REGNO (rcontext) && i != REGNO (rsp))
2747194246Smarius      break;
2748194246Smarius  if (i == FIRST_PSEUDO_REGISTER)
2749194246Smarius    abort();
2750194246Smarius
2751194246Smarius  rra = gen_rtx_REG (Pmode, i);
2752194246Smarius
2753194246Smarius  *pcontext = rcontext;
2754194246Smarius  *psp = rsp;
2755194246Smarius  *pra = rra;
2756194246Smarius}
2757194246Smarius
2758194246Smarius/* Retrieve the register which contains the pointer to the eh_context
2759194246Smarius   structure set the __throw. */
2760194246Smarius
2761194246Smariusrtx
2762194246Smariusget_reg_for_handler ()
2763194246Smarius{
2764194246Smarius  rtx reg1;
2765194246Smarius  reg1 = FUNCTION_VALUE (build_pointer_type (void_type_node),
2766194246Smarius			   current_function_decl);
2767194246Smarius  return reg1;
2768194246Smarius}
2769194246Smarius
2770194246Smarius/* Set up the epilogue with the magic bits we'll need to return to the
2771207585Smarius   exception handler.  */
2772207585Smarius
2773207585Smariusvoid
2774207585Smariusexpand_builtin_eh_return (context, stack, handler)
2775194246Smarius    tree context, stack, handler;
2776194246Smarius{
2777194246Smarius  if (eh_return_context)
2778194246Smarius    error("Duplicate call to __builtin_eh_return");
2779194246Smarius
2780194246Smarius  eh_return_context
2781194246Smarius    = copy_to_reg (expand_expr (context, NULL_RTX, VOIDmode, 0));
2782194246Smarius  eh_return_stack_adjust
2783194246Smarius    = copy_to_reg (expand_expr (stack, NULL_RTX, VOIDmode, 0));
2784194246Smarius  eh_return_handler
2785194246Smarius    = copy_to_reg (expand_expr (handler, NULL_RTX, VOIDmode, 0));
2786194246Smarius}
2787194246Smarius
2788194246Smariusvoid
2789194246Smariusexpand_eh_return ()
2790194246Smarius{
2791194246Smarius  rtx reg1, reg2, reg3;
2792194246Smarius  rtx stub_start, after_stub;
2793194246Smarius  rtx ra, tmp;
2794194246Smarius
2795194246Smarius  if (!eh_return_context)
2796194246Smarius    return;
2797194246Smarius
2798194246Smarius  current_function_cannot_inline = N_("function uses __builtin_eh_return");
2799194246Smarius
2800194246Smarius  eh_regs (&reg1, &reg2, &reg3, 1);
2801194246Smarius#ifdef POINTERS_EXTEND_UNSIGNED
2802194246Smarius  eh_return_context = convert_memory_address (Pmode, eh_return_context);
2803194246Smarius  eh_return_stack_adjust =
2804194246Smarius      convert_memory_address (Pmode, eh_return_stack_adjust);
2805194246Smarius  eh_return_handler = convert_memory_address (Pmode, eh_return_handler);
2806194246Smarius#endif
2807194246Smarius  emit_move_insn (reg1, eh_return_context);
2808194246Smarius  emit_move_insn (reg2, eh_return_stack_adjust);
2809194246Smarius  emit_move_insn (reg3, eh_return_handler);
2810194246Smarius
2811194246Smarius  /* Talk directly to the target's epilogue code when possible.  */
2812194246Smarius
2813194246Smarius#ifdef HAVE_eh_epilogue
2814194246Smarius  if (HAVE_eh_epilogue)
2815194246Smarius    {
2816194246Smarius      emit_insn (gen_eh_epilogue (reg1, reg2, reg3));
2817194246Smarius      return;
2818194246Smarius    }
2819194246Smarius#endif
2820194246Smarius
2821194246Smarius  /* Otherwise, use the same stub technique we had before.  */
2822194246Smarius
2823207585Smarius  eh_return_stub_label = stub_start = gen_label_rtx ();
2824207585Smarius  after_stub = gen_label_rtx ();
2825207585Smarius
2826207585Smarius  /* Set the return address to the stub label.  */
2827207585Smarius
2828207585Smarius  ra = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
2829207585Smarius				   0, hard_frame_pointer_rtx);
2830207585Smarius  if (GET_CODE (ra) == REG && REGNO (ra) >= FIRST_PSEUDO_REGISTER)
2831207585Smarius    abort();
2832207585Smarius
2833207585Smarius  tmp = memory_address (Pmode, gen_rtx_LABEL_REF (Pmode, stub_start));
2834207585Smarius#ifdef RETURN_ADDR_OFFSET
2835207585Smarius  tmp = plus_constant (tmp, -RETURN_ADDR_OFFSET);
2836207585Smarius#endif
2837207585Smarius  tmp = force_operand (tmp, ra);
2838207585Smarius  if (tmp != ra)
2839207585Smarius    emit_move_insn (ra, tmp);
2840207585Smarius
2841207585Smarius  /* Indicate that the registers are in fact used.  */
2842207585Smarius  emit_insn (gen_rtx_USE (VOIDmode, reg1));
2843207585Smarius  emit_insn (gen_rtx_USE (VOIDmode, reg2));
2844207585Smarius  emit_insn (gen_rtx_USE (VOIDmode, reg3));
2845207585Smarius  if (GET_CODE (ra) == REG)
2846207585Smarius    emit_insn (gen_rtx_USE (VOIDmode, ra));
2847207585Smarius
2848207585Smarius  /* Generate the stub.  */
2849207585Smarius
2850207585Smarius  emit_jump (after_stub);
2851207585Smarius  emit_label (stub_start);
2852207585Smarius
2853207585Smarius  eh_regs (&reg1, &reg2, &reg3, 0);
2854207585Smarius  adjust_stack (reg2);
2855207585Smarius  emit_indirect_jump (reg3);
2856207585Smarius
2857207585Smarius  emit_label (after_stub);
2858207585Smarius}
2859207585Smarius
2860207585Smarius
2861207585Smarius/* This contains the code required to verify whether arbitrary instructions
2862207585Smarius   are in the same exception region. */
2863207585Smarius
2864207585Smariusstatic int *insn_eh_region = (int *)0;
2865207585Smariusstatic int maximum_uid;
2866207585Smarius
2867207585Smariusstatic void
2868194246Smariusset_insn_eh_region (first, region_num)
2869194246Smarius     rtx *first;
2870194246Smarius     int region_num;
2871194246Smarius{
2872194246Smarius  rtx insn;
2873194246Smarius  int rnum;
2874194246Smarius
2875194246Smarius  for (insn = *first; insn; insn = NEXT_INSN (insn))
2876194246Smarius    {
2877194246Smarius      if ((GET_CODE (insn) == NOTE) &&
2878207585Smarius                        (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG))
2879194246Smarius        {
2880194246Smarius          rnum = NOTE_BLOCK_NUMBER (insn);
2881194246Smarius          insn_eh_region[INSN_UID (insn)] =  rnum;
2882194246Smarius          insn = NEXT_INSN (insn);
2883245923Smarius          set_insn_eh_region (&insn, rnum);
2884194246Smarius          /* Upon return, insn points to the EH_REGION_END of nested region */
2885194246Smarius          continue;
2886207585Smarius        }
2887207585Smarius      insn_eh_region[INSN_UID (insn)] = region_num;
2888207585Smarius      if ((GET_CODE (insn) == NOTE) &&
2889207585Smarius            (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
2890207585Smarius        break;
2891207585Smarius    }
2892245923Smarius  *first = insn;
2893207585Smarius}
2894207585Smarius
2895207585Smarius/* Free the insn table, an make sure it cannot be used again. */
2896194246Smarius
2897194246Smariusvoid
2898194246Smariusfree_insn_eh_region ()
2899194246Smarius{
2900194246Smarius  if (!doing_eh (0))
2901194246Smarius    return;
2902194246Smarius
2903194246Smarius  if (insn_eh_region)
2904194904Smarius    {
2905194246Smarius      free (insn_eh_region);
2906194246Smarius      insn_eh_region = (int *)0;
2907194246Smarius    }
2908194246Smarius}
2909194246Smarius
2910194246Smarius/* Initialize the table. max_uid must be calculated and handed into
2911194246Smarius   this routine. If it is unavailable, passing a value of 0 will
2912194246Smarius   cause this routine to calculate it as well. */
2913194246Smarius
2914194246Smariusvoid
2915194246Smariusinit_insn_eh_region (first, max_uid)
2916194246Smarius     rtx first;
2917194246Smarius     int max_uid;
2918194246Smarius{
2919194246Smarius  rtx insn;
2920194246Smarius
2921194246Smarius  if (!doing_eh (0))
2922194246Smarius    return;
2923194246Smarius
2924194246Smarius  if (insn_eh_region)
2925194246Smarius    free_insn_eh_region();
2926194246Smarius
2927194246Smarius  if (max_uid == 0)
2928194246Smarius    for (insn = first; insn; insn = NEXT_INSN (insn))
2929194246Smarius      if (INSN_UID (insn) > max_uid)       /* find largest UID */
2930194246Smarius        max_uid = INSN_UID (insn);
2931194246Smarius
2932194246Smarius  maximum_uid = max_uid;
2933194246Smarius  insn_eh_region = (int *) malloc ((max_uid + 1) * sizeof (int));
2934194246Smarius  insn = first;
2935194246Smarius  set_insn_eh_region (&insn, 0);
2936194246Smarius}
2937194246Smarius
2938194246Smarius
2939194246Smarius/* Check whether 2 instructions are within the same region. */
2940194246Smarius
2941194246Smariusint
2942194246Smariusin_same_eh_region (insn1, insn2)
2943194246Smarius     rtx insn1, insn2;
2944194246Smarius{
2945  int ret, uid1, uid2;
2946
2947  /* If no exceptions, instructions are always in same region. */
2948  if (!doing_eh (0))
2949    return 1;
2950
2951  /* If the table isn't allocated, assume the worst. */
2952  if (!insn_eh_region)
2953    return 0;
2954
2955  uid1 = INSN_UID (insn1);
2956  uid2 = INSN_UID (insn2);
2957
2958  /* if instructions have been allocated beyond the end, either
2959     the table is out of date, or this is a late addition, or
2960     something... Assume the worst. */
2961  if (uid1 > maximum_uid || uid2 > maximum_uid)
2962    return 0;
2963
2964  ret = (insn_eh_region[uid1] == insn_eh_region[uid2]);
2965  return ret;
2966}
2967
2968