150397Sobrien/* Implements exception handling.
290075Sobrien   Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3169689Skan   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
450397Sobrien   Contributed by Mike Stump <mrs@cygnus.com>.
550397Sobrien
690075SobrienThis file is part of GCC.
750397Sobrien
890075SobrienGCC is free software; you can redistribute it and/or modify it under
990075Sobrienthe terms of the GNU General Public License as published by the Free
1090075SobrienSoftware Foundation; either version 2, or (at your option) any later
1190075Sobrienversion.
1250397Sobrien
1390075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1490075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1590075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1690075Sobrienfor more details.
1750397Sobrien
1850397SobrienYou should have received a copy of the GNU General Public License
1990075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
20169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
21169689Skan02110-1301, USA.  */
2250397Sobrien
2350397Sobrien
2450397Sobrien/* An exception is an event that can be signaled from within a
2550397Sobrien   function. This event can then be "caught" or "trapped" by the
2650397Sobrien   callers of this function. This potentially allows program flow to
2750397Sobrien   be transferred to any arbitrary code associated with a function call
2850397Sobrien   several levels up the stack.
2950397Sobrien
3050397Sobrien   The intended use for this mechanism is for signaling "exceptional
3150397Sobrien   events" in an out-of-band fashion, hence its name. The C++ language
3250397Sobrien   (and many other OO-styled or functional languages) practically
3350397Sobrien   requires such a mechanism, as otherwise it becomes very difficult
3450397Sobrien   or even impossible to signal failure conditions in complex
3550397Sobrien   situations.  The traditional C++ example is when an error occurs in
3650397Sobrien   the process of constructing an object; without such a mechanism, it
3750397Sobrien   is impossible to signal that the error occurs without adding global
3850397Sobrien   state variables and error checks around every object construction.
3950397Sobrien
4050397Sobrien   The act of causing this event to occur is referred to as "throwing
4150397Sobrien   an exception". (Alternate terms include "raising an exception" or
4250397Sobrien   "signaling an exception".) The term "throw" is used because control
4350397Sobrien   is returned to the callers of the function that is signaling the
4450397Sobrien   exception, and thus there is the concept of "throwing" the
4550397Sobrien   exception up the call stack.
4650397Sobrien
4790075Sobrien   [ Add updated documentation on how to use this.  ]  */
4850397Sobrien
4950397Sobrien
5090075Sobrien#include "config.h"
5190075Sobrien#include "system.h"
52132718Skan#include "coretypes.h"
53132718Skan#include "tm.h"
5490075Sobrien#include "rtl.h"
5590075Sobrien#include "tree.h"
5690075Sobrien#include "flags.h"
5790075Sobrien#include "function.h"
5890075Sobrien#include "expr.h"
5990075Sobrien#include "libfuncs.h"
6090075Sobrien#include "insn-config.h"
6190075Sobrien#include "except.h"
6290075Sobrien#include "integrate.h"
6390075Sobrien#include "hard-reg-set.h"
6490075Sobrien#include "basic-block.h"
6590075Sobrien#include "output.h"
6690075Sobrien#include "dwarf2asm.h"
6790075Sobrien#include "dwarf2out.h"
6890075Sobrien#include "dwarf2.h"
6990075Sobrien#include "toplev.h"
7090075Sobrien#include "hashtab.h"
7190075Sobrien#include "intl.h"
7290075Sobrien#include "ggc.h"
7390075Sobrien#include "tm_p.h"
7490075Sobrien#include "target.h"
75117395Skan#include "langhooks.h"
76132718Skan#include "cgraph.h"
77169689Skan#include "diagnostic.h"
78169689Skan#include "tree-pass.h"
79169689Skan#include "timevar.h"
8050397Sobrien
8190075Sobrien/* Provide defaults for stuff that may not be defined when using
8290075Sobrien   sjlj exceptions.  */
8390075Sobrien#ifndef EH_RETURN_DATA_REGNO
8490075Sobrien#define EH_RETURN_DATA_REGNO(N) INVALID_REGNUM
8590075Sobrien#endif
8650397Sobrien
8750397Sobrien
8890075Sobrien/* Protect cleanup actions with must-not-throw regions, with a call
8990075Sobrien   to the given failure handler.  */
90132718Skantree (*lang_protect_cleanup_actions) (void);
9150397Sobrien
9290075Sobrien/* Return true if type A catches type B.  */
93132718Skanint (*lang_eh_type_covers) (tree a, tree b);
9450397Sobrien
9590075Sobrien/* Map a type to a runtime object to match type.  */
96132718Skantree (*lang_eh_runtime_type) (tree);
9750397Sobrien
9896263Sobrien/* A hash table of label to region number.  */
9950397Sobrien
100117395Skanstruct ehl_map_entry GTY(())
10196263Sobrien{
10296263Sobrien  rtx label;
10396263Sobrien  struct eh_region *region;
10496263Sobrien};
10596263Sobrien
106132718Skanstatic GTY(()) int call_site_base;
107117395Skanstatic GTY ((param_is (union tree_node)))
108117395Skan  htab_t type_to_runtime_map;
10950397Sobrien
11090075Sobrien/* Describe the SjLj_Function_Context structure.  */
111117395Skanstatic GTY(()) tree sjlj_fc_type_node;
11290075Sobrienstatic int sjlj_fc_call_site_ofs;
11390075Sobrienstatic int sjlj_fc_data_ofs;
11490075Sobrienstatic int sjlj_fc_personality_ofs;
11590075Sobrienstatic int sjlj_fc_lsda_ofs;
11690075Sobrienstatic int sjlj_fc_jbuf_ofs;
11790075Sobrien
11890075Sobrien/* Describes one exception region.  */
119117395Skanstruct eh_region GTY(())
12090075Sobrien{
12190075Sobrien  /* The immediately surrounding region.  */
12290075Sobrien  struct eh_region *outer;
12350397Sobrien
12490075Sobrien  /* The list of immediately contained regions.  */
12590075Sobrien  struct eh_region *inner;
12690075Sobrien  struct eh_region *next_peer;
12750397Sobrien
12890075Sobrien  /* An identifier for this region.  */
12990075Sobrien  int region_number;
13050397Sobrien
13196263Sobrien  /* When a region is deleted, its parents inherit the REG_EH_REGION
13296263Sobrien     numbers already assigned.  */
13396263Sobrien  bitmap aka;
13496263Sobrien
13590075Sobrien  /* Each region does exactly one thing.  */
13690075Sobrien  enum eh_region_type
13790075Sobrien  {
13890075Sobrien    ERT_UNKNOWN = 0,
13990075Sobrien    ERT_CLEANUP,
14090075Sobrien    ERT_TRY,
14190075Sobrien    ERT_CATCH,
14290075Sobrien    ERT_ALLOWED_EXCEPTIONS,
14390075Sobrien    ERT_MUST_NOT_THROW,
144169689Skan    ERT_THROW
14590075Sobrien  } type;
14650397Sobrien
14790075Sobrien  /* Holds the action to perform based on the preceding type.  */
148117395Skan  union eh_region_u {
14990075Sobrien    /* A list of catch blocks, a surrounding try block,
15090075Sobrien       and the label for continuing after a catch.  */
151117395Skan    struct eh_region_u_try {
15290075Sobrien      struct eh_region *catch;
15390075Sobrien      struct eh_region *last_catch;
154117395Skan    } GTY ((tag ("ERT_TRY"))) try;
15550397Sobrien
15690075Sobrien    /* The list through the catch handlers, the list of type objects
15790075Sobrien       matched, and the list of associated filters.  */
158117395Skan    struct eh_region_u_catch {
15990075Sobrien      struct eh_region *next_catch;
16090075Sobrien      struct eh_region *prev_catch;
16190075Sobrien      tree type_list;
16290075Sobrien      tree filter_list;
163117395Skan    } GTY ((tag ("ERT_CATCH"))) catch;
16450397Sobrien
16590075Sobrien    /* A tree_list of allowed types.  */
166117395Skan    struct eh_region_u_allowed {
16790075Sobrien      tree type_list;
16890075Sobrien      int filter;
169117395Skan    } GTY ((tag ("ERT_ALLOWED_EXCEPTIONS"))) allowed;
17050397Sobrien
17190075Sobrien    /* The type given by a call to "throw foo();", or discovered
17290075Sobrien       for a throw.  */
173117395Skan    struct eh_region_u_throw {
17490075Sobrien      tree type;
175117395Skan    } GTY ((tag ("ERT_THROW"))) throw;
17650397Sobrien
17790075Sobrien    /* Retain the cleanup expression even after expansion so that
17890075Sobrien       we can match up fixup regions.  */
179117395Skan    struct eh_region_u_cleanup {
180117395Skan      struct eh_region *prev_try;
181117395Skan    } GTY ((tag ("ERT_CLEANUP"))) cleanup;
182117395Skan  } GTY ((desc ("%0.type"))) u;
18350397Sobrien
18490075Sobrien  /* Entry point for this region's handler before landing pads are built.  */
18590075Sobrien  rtx label;
186169689Skan  tree tree_label;
18750397Sobrien
18890075Sobrien  /* Entry point for this region's handler from the runtime eh library.  */
18990075Sobrien  rtx landing_pad;
19050397Sobrien
19190075Sobrien  /* Entry point for this region's handler from an inner region.  */
19290075Sobrien  rtx post_landing_pad;
19350397Sobrien
19490075Sobrien  /* The RESX insn for handing off control to the next outermost handler,
19590075Sobrien     if appropriate.  */
19690075Sobrien  rtx resume;
197117395Skan
198117395Skan  /* True if something in this region may throw.  */
199117395Skan  unsigned may_contain_throw : 1;
20090075Sobrien};
20150397Sobrien
202169689Skantypedef struct eh_region *eh_region;
203169689Skan
204117395Skanstruct call_site_record GTY(())
205117395Skan{
206117395Skan  rtx landing_pad;
207117395Skan  int action;
208117395Skan};
209117395Skan
210169689SkanDEF_VEC_P(eh_region);
211169689SkanDEF_VEC_ALLOC_P(eh_region, gc);
212169689Skan
21390075Sobrien/* Used to save exception status for each function.  */
214117395Skanstruct eh_status GTY(())
21590075Sobrien{
21690075Sobrien  /* The tree of all regions for this function.  */
21790075Sobrien  struct eh_region *region_tree;
21850397Sobrien
21990075Sobrien  /* The same information as an indexable array.  */
220169689Skan  VEC(eh_region,gc) *region_array;
22150397Sobrien
22290075Sobrien  /* The most recently open region.  */
22390075Sobrien  struct eh_region *cur_region;
22450397Sobrien
22590075Sobrien  /* This is the region for which we are processing catch blocks.  */
22690075Sobrien  struct eh_region *try_region;
22750397Sobrien
22890075Sobrien  rtx filter;
22990075Sobrien  rtx exc_ptr;
23050397Sobrien
23190075Sobrien  int built_landing_pads;
23290075Sobrien  int last_region_number;
23350397Sobrien
234169689Skan  VEC(tree,gc) *ttype_data;
23590075Sobrien  varray_type ehspec_data;
23690075Sobrien  varray_type action_record_data;
23750397Sobrien
238117395Skan  htab_t GTY ((param_is (struct ehl_map_entry))) exception_handler_label_map;
239117395Skan
240132718Skan  struct call_site_record * GTY ((length ("%h.call_site_data_used")))
241117395Skan    call_site_data;
24290075Sobrien  int call_site_data_used;
24390075Sobrien  int call_site_data_size;
24450397Sobrien
24590075Sobrien  rtx ehr_stackadj;
24690075Sobrien  rtx ehr_handler;
24790075Sobrien  rtx ehr_label;
24850397Sobrien
24990075Sobrien  rtx sjlj_fc;
25090075Sobrien  rtx sjlj_exit_after;
251169689Skan
252169689Skan  htab_t GTY((param_is (struct throw_stmt_node))) throw_stmt_table;
25390075Sobrien};
25490075Sobrien
255132718Skanstatic int t2r_eq (const void *, const void *);
256132718Skanstatic hashval_t t2r_hash (const void *);
257132718Skanstatic void add_type_for_runtime (tree);
258132718Skanstatic tree lookup_type_for_runtime (tree);
25950397Sobrien
260132718Skanstatic void remove_unreachable_regions (rtx);
26150397Sobrien
262132718Skanstatic int ttypes_filter_eq (const void *, const void *);
263132718Skanstatic hashval_t ttypes_filter_hash (const void *);
264132718Skanstatic int ehspec_filter_eq (const void *, const void *);
265132718Skanstatic hashval_t ehspec_filter_hash (const void *);
266132718Skanstatic int add_ttypes_entry (htab_t, tree);
267132718Skanstatic int add_ehspec_entry (htab_t, htab_t, tree);
268132718Skanstatic void assign_filter_values (void);
269132718Skanstatic void build_post_landing_pads (void);
270132718Skanstatic void connect_post_landing_pads (void);
271132718Skanstatic void dw2_build_landing_pads (void);
27250397Sobrien
27390075Sobrienstruct sjlj_lp_info;
274132718Skanstatic bool sjlj_find_directly_reachable_regions (struct sjlj_lp_info *);
275132718Skanstatic void sjlj_assign_call_site_values (rtx, struct sjlj_lp_info *);
276132718Skanstatic void sjlj_mark_call_sites (struct sjlj_lp_info *);
277132718Skanstatic void sjlj_emit_function_enter (rtx);
278132718Skanstatic void sjlj_emit_function_exit (void);
279132718Skanstatic void sjlj_emit_dispatch_table (rtx, struct sjlj_lp_info *);
280132718Skanstatic void sjlj_build_landing_pads (void);
28150397Sobrien
282132718Skanstatic hashval_t ehl_hash (const void *);
283132718Skanstatic int ehl_eq (const void *, const void *);
284132718Skanstatic void add_ehl_entry (rtx, struct eh_region *);
285132718Skanstatic void remove_exception_handler_label (rtx);
286132718Skanstatic void remove_eh_handler (struct eh_region *);
287132718Skanstatic int for_each_eh_label_1 (void **, void *);
28850397Sobrien
28990075Sobrien/* The return value of reachable_next_level.  */
29090075Sobrienenum reachable_code
29190075Sobrien{
29290075Sobrien  /* The given exception is not processed by the given region.  */
29390075Sobrien  RNL_NOT_CAUGHT,
29490075Sobrien  /* The given exception may need processing by the given region.  */
29590075Sobrien  RNL_MAYBE_CAUGHT,
29690075Sobrien  /* The given exception is completely processed by the given region.  */
29790075Sobrien  RNL_CAUGHT,
29890075Sobrien  /* The given exception is completely processed by the runtime.  */
29990075Sobrien  RNL_BLOCKED
30090075Sobrien};
30150397Sobrien
302169689Skanstruct reachable_info;
303132718Skanstatic enum reachable_code reachable_next_level (struct eh_region *, tree,
304132718Skan						 struct reachable_info *);
30550397Sobrien
306132718Skanstatic int action_record_eq (const void *, const void *);
307132718Skanstatic hashval_t action_record_hash (const void *);
308132718Skanstatic int add_action_record (htab_t, int, int);
309132718Skanstatic int collect_one_action_chain (htab_t, struct eh_region *);
310132718Skanstatic int add_call_site (rtx, int);
31150397Sobrien
312132718Skanstatic void push_uleb128 (varray_type *, unsigned int);
313132718Skanstatic void push_sleb128 (varray_type *, int);
31490075Sobrien#ifndef HAVE_AS_LEB128
315132718Skanstatic int dw2_size_of_call_site_table (void);
316132718Skanstatic int sjlj_size_of_call_site_table (void);
31790075Sobrien#endif
318132718Skanstatic void dw2_output_call_site_table (void);
319132718Skanstatic void sjlj_output_call_site_table (void);
32050397Sobrien
32190075Sobrien
32290075Sobrien/* Routine to see if exception handling is turned on.
323117395Skan   DO_WARN is nonzero if we want to inform the user that exception
32490075Sobrien   handling is turned off.
32550397Sobrien
32690075Sobrien   This is used to ensure that -fexceptions has been specified if the
32790075Sobrien   compiler tries to use any exception-specific functions.  */
32850397Sobrien
32990075Sobrienint
330132718Skandoing_eh (int do_warn)
33190075Sobrien{
33290075Sobrien  if (! flag_exceptions)
33390075Sobrien    {
33490075Sobrien      static int warned = 0;
33590075Sobrien      if (! warned && do_warn)
33690075Sobrien	{
33790075Sobrien	  error ("exception handling disabled, use -fexceptions to enable");
33890075Sobrien	  warned = 1;
33990075Sobrien	}
34090075Sobrien      return 0;
34190075Sobrien    }
34290075Sobrien  return 1;
34390075Sobrien}
34450397Sobrien
34590075Sobrien
34690075Sobrienvoid
347132718Skaninit_eh (void)
34890075Sobrien{
34990075Sobrien  if (! flag_exceptions)
35090075Sobrien    return;
35150397Sobrien
352117395Skan  type_to_runtime_map = htab_create_ggc (31, t2r_hash, t2r_eq, NULL);
35350397Sobrien
35490075Sobrien  /* Create the SjLj_Function_Context structure.  This should match
35590075Sobrien     the definition in unwind-sjlj.c.  */
35690075Sobrien  if (USING_SJLJ_EXCEPTIONS)
35790075Sobrien    {
35890075Sobrien      tree f_jbuf, f_per, f_lsda, f_prev, f_cs, f_data, tmp;
35950397Sobrien
360169689Skan      sjlj_fc_type_node = lang_hooks.types.make_type (RECORD_TYPE);
36150397Sobrien
36290075Sobrien      f_prev = build_decl (FIELD_DECL, get_identifier ("__prev"),
36390075Sobrien			   build_pointer_type (sjlj_fc_type_node));
36490075Sobrien      DECL_FIELD_CONTEXT (f_prev) = sjlj_fc_type_node;
36550397Sobrien
36690075Sobrien      f_cs = build_decl (FIELD_DECL, get_identifier ("__call_site"),
36790075Sobrien			 integer_type_node);
36890075Sobrien      DECL_FIELD_CONTEXT (f_cs) = sjlj_fc_type_node;
36950397Sobrien
370169689Skan      tmp = build_index_type (build_int_cst (NULL_TREE, 4 - 1));
371169689Skan      tmp = build_array_type (lang_hooks.types.type_for_mode (word_mode, 1),
372117395Skan			      tmp);
37390075Sobrien      f_data = build_decl (FIELD_DECL, get_identifier ("__data"), tmp);
37490075Sobrien      DECL_FIELD_CONTEXT (f_data) = sjlj_fc_type_node;
37550397Sobrien
37690075Sobrien      f_per = build_decl (FIELD_DECL, get_identifier ("__personality"),
37790075Sobrien			  ptr_type_node);
37890075Sobrien      DECL_FIELD_CONTEXT (f_per) = sjlj_fc_type_node;
37950397Sobrien
38090075Sobrien      f_lsda = build_decl (FIELD_DECL, get_identifier ("__lsda"),
38190075Sobrien			   ptr_type_node);
38290075Sobrien      DECL_FIELD_CONTEXT (f_lsda) = sjlj_fc_type_node;
38350397Sobrien
38490075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP
38590075Sobrien#ifdef JMP_BUF_SIZE
386169689Skan      tmp = build_int_cst (NULL_TREE, JMP_BUF_SIZE - 1);
38790075Sobrien#else
38890075Sobrien      /* Should be large enough for most systems, if it is not,
38990075Sobrien	 JMP_BUF_SIZE should be defined with the proper value.  It will
39090075Sobrien	 also tend to be larger than necessary for most systems, a more
39190075Sobrien	 optimal port will define JMP_BUF_SIZE.  */
392169689Skan      tmp = build_int_cst (NULL_TREE, FIRST_PSEUDO_REGISTER + 2 - 1);
39390075Sobrien#endif
39490075Sobrien#else
395132718Skan      /* builtin_setjmp takes a pointer to 5 words.  */
396169689Skan      tmp = build_int_cst (NULL_TREE, 5 * BITS_PER_WORD / POINTER_SIZE - 1);
39790075Sobrien#endif
39890075Sobrien      tmp = build_index_type (tmp);
39990075Sobrien      tmp = build_array_type (ptr_type_node, tmp);
40090075Sobrien      f_jbuf = build_decl (FIELD_DECL, get_identifier ("__jbuf"), tmp);
40190075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP
40290075Sobrien      /* We don't know what the alignment requirements of the
40390075Sobrien	 runtime's jmp_buf has.  Overestimate.  */
40490075Sobrien      DECL_ALIGN (f_jbuf) = BIGGEST_ALIGNMENT;
40590075Sobrien      DECL_USER_ALIGN (f_jbuf) = 1;
40690075Sobrien#endif
40790075Sobrien      DECL_FIELD_CONTEXT (f_jbuf) = sjlj_fc_type_node;
40850397Sobrien
40990075Sobrien      TYPE_FIELDS (sjlj_fc_type_node) = f_prev;
41090075Sobrien      TREE_CHAIN (f_prev) = f_cs;
41190075Sobrien      TREE_CHAIN (f_cs) = f_data;
41290075Sobrien      TREE_CHAIN (f_data) = f_per;
41390075Sobrien      TREE_CHAIN (f_per) = f_lsda;
41490075Sobrien      TREE_CHAIN (f_lsda) = f_jbuf;
41550397Sobrien
41690075Sobrien      layout_type (sjlj_fc_type_node);
41750397Sobrien
41890075Sobrien      /* Cache the interesting field offsets so that we have
41990075Sobrien	 easy access from rtl.  */
42090075Sobrien      sjlj_fc_call_site_ofs
42190075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_cs), 1)
42290075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_cs), 1) / BITS_PER_UNIT);
42390075Sobrien      sjlj_fc_data_ofs
42490075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_data), 1)
42590075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_data), 1) / BITS_PER_UNIT);
42690075Sobrien      sjlj_fc_personality_ofs
42790075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_per), 1)
42890075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_per), 1) / BITS_PER_UNIT);
42990075Sobrien      sjlj_fc_lsda_ofs
43090075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_lsda), 1)
43190075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_lsda), 1) / BITS_PER_UNIT);
43290075Sobrien      sjlj_fc_jbuf_ofs
43390075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_jbuf), 1)
43490075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_jbuf), 1) / BITS_PER_UNIT);
43590075Sobrien    }
43690075Sobrien}
43750397Sobrien
43890075Sobrienvoid
439132718Skaninit_eh_for_function (void)
44090075Sobrien{
441132718Skan  cfun->eh = ggc_alloc_cleared (sizeof (struct eh_status));
44290075Sobrien}
44390075Sobrien
444169689Skan/* Routines to generate the exception tree somewhat directly.
445169689Skan   These are used from tree-eh.c when processing exception related
446169689Skan   nodes during tree optimization.  */
44750397Sobrien
448169689Skanstatic struct eh_region *
449169689Skangen_eh_region (enum eh_region_type type, struct eh_region *outer)
45090075Sobrien{
451169689Skan  struct eh_region *new;
45252284Sobrien
453169689Skan#ifdef ENABLE_CHECKING
454169689Skan  gcc_assert (doing_eh (0));
455169689Skan#endif
45652284Sobrien
45790075Sobrien  /* Insert a new blank region as a leaf in the tree.  */
458169689Skan  new = ggc_alloc_cleared (sizeof (*new));
459169689Skan  new->type = type;
460169689Skan  new->outer = outer;
461169689Skan  if (outer)
46290075Sobrien    {
463169689Skan      new->next_peer = outer->inner;
464169689Skan      outer->inner = new;
46590075Sobrien    }
46690075Sobrien  else
46790075Sobrien    {
468169689Skan      new->next_peer = cfun->eh->region_tree;
469169689Skan      cfun->eh->region_tree = new;
47090075Sobrien    }
47152284Sobrien
472169689Skan  new->region_number = ++cfun->eh->last_region_number;
47352284Sobrien
474169689Skan  return new;
47590075Sobrien}
47650397Sobrien
477169689Skanstruct eh_region *
478169689Skangen_eh_region_cleanup (struct eh_region *outer, struct eh_region *prev_try)
47952284Sobrien{
480169689Skan  struct eh_region *cleanup = gen_eh_region (ERT_CLEANUP, outer);
481169689Skan  cleanup->u.cleanup.prev_try = prev_try;
482169689Skan  return cleanup;
48350397Sobrien}
48450397Sobrien
485169689Skanstruct eh_region *
486169689Skangen_eh_region_try (struct eh_region *outer)
48750397Sobrien{
488169689Skan  return gen_eh_region (ERT_TRY, outer);
48950397Sobrien}
49050397Sobrien
491169689Skanstruct eh_region *
492169689Skangen_eh_region_catch (struct eh_region *t, tree type_or_list)
49350397Sobrien{
494169689Skan  struct eh_region *c, *l;
495169689Skan  tree type_list, type_node;
49650397Sobrien
497169689Skan  /* Ensure to always end up with a type list to normalize further
498169689Skan     processing, then register each type against the runtime types map.  */
49990075Sobrien  type_list = type_or_list;
50090075Sobrien  if (type_or_list)
50190075Sobrien    {
50290075Sobrien      if (TREE_CODE (type_or_list) != TREE_LIST)
503117395Skan	type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE);
50490075Sobrien
50590075Sobrien      type_node = type_list;
50690075Sobrien      for (; type_node; type_node = TREE_CHAIN (type_node))
507117395Skan	add_type_for_runtime (TREE_VALUE (type_node));
50890075Sobrien    }
50990075Sobrien
510169689Skan  c = gen_eh_region (ERT_CATCH, t->outer);
51190075Sobrien  c->u.catch.type_list = type_list;
51290075Sobrien  l = t->u.try.last_catch;
51390075Sobrien  c->u.catch.prev_catch = l;
51490075Sobrien  if (l)
51590075Sobrien    l->u.catch.next_catch = c;
51652284Sobrien  else
51790075Sobrien    t->u.try.catch = c;
51890075Sobrien  t->u.try.last_catch = c;
51950397Sobrien
520169689Skan  return c;
52150397Sobrien}
52250397Sobrien
523169689Skanstruct eh_region *
524169689Skangen_eh_region_allowed (struct eh_region *outer, tree allowed)
52550397Sobrien{
526169689Skan  struct eh_region *region = gen_eh_region (ERT_ALLOWED_EXCEPTIONS, outer);
527169689Skan  region->u.allowed.type_list = allowed;
52850397Sobrien
529169689Skan  for (; allowed ; allowed = TREE_CHAIN (allowed))
530169689Skan    add_type_for_runtime (TREE_VALUE (allowed));
53150397Sobrien
532169689Skan  return region;
533169689Skan}
53450397Sobrien
535169689Skanstruct eh_region *
536169689Skangen_eh_region_must_not_throw (struct eh_region *outer)
537169689Skan{
538169689Skan  return gen_eh_region (ERT_MUST_NOT_THROW, outer);
53950397Sobrien}
54050397Sobrien
541169689Skanint
542169689Skanget_eh_region_number (struct eh_region *region)
54350397Sobrien{
544169689Skan  return region->region_number;
54550397Sobrien}
54650397Sobrien
547169689Skanbool
548169689Skanget_eh_region_may_contain_throw (struct eh_region *region)
54950397Sobrien{
550169689Skan  return region->may_contain_throw;
55150397Sobrien}
55250397Sobrien
553169689Skantree
554169689Skanget_eh_region_tree_label (struct eh_region *region)
55550397Sobrien{
556169689Skan  return region->tree_label;
55750397Sobrien}
55850397Sobrien
55990075Sobrienvoid
560169689Skanset_eh_region_tree_label (struct eh_region *region, tree lab)
56150397Sobrien{
562169689Skan  region->tree_label = lab;
56390075Sobrien}
564169689Skan
56590075Sobrienvoid
566169689Skanexpand_resx_expr (tree exp)
56750397Sobrien{
568169689Skan  int region_nr = TREE_INT_CST_LOW (TREE_OPERAND (exp, 0));
569169689Skan  struct eh_region *reg = VEC_index (eh_region,
570169689Skan				     cfun->eh->region_array, region_nr);
57150397Sobrien
572169689Skan  gcc_assert (!reg->resume);
573169689Skan  reg->resume = emit_jump_insn (gen_rtx_RESX (VOIDmode, region_nr));
574169689Skan  emit_barrier ();
57550397Sobrien}
57650397Sobrien
577117395Skan/* Note that the current EH region (if any) may contain a throw, or a
578117395Skan   call to a function which itself may contain a throw.  */
579117395Skan
580117395Skanvoid
581169689Skannote_eh_region_may_contain_throw (struct eh_region *region)
582117395Skan{
583117395Skan  while (region && !region->may_contain_throw)
584117395Skan    {
585117395Skan      region->may_contain_throw = 1;
586117395Skan      region = region->outer;
587117395Skan    }
588117395Skan}
589117395Skan
590169689Skanvoid
591169689Skannote_current_region_may_contain_throw (void)
592169689Skan{
593169689Skan  note_eh_region_may_contain_throw (cfun->eh->cur_region);
594169689Skan}
595169689Skan
596169689Skan
59790075Sobrien/* Return an rtl expression for a pointer to the exception object
59890075Sobrien   within a handler.  */
59950397Sobrien
60090075Sobrienrtx
601132718Skanget_exception_pointer (struct function *fun)
60250397Sobrien{
60390075Sobrien  rtx exc_ptr = fun->eh->exc_ptr;
60490075Sobrien  if (fun == cfun && ! exc_ptr)
60550397Sobrien    {
606117395Skan      exc_ptr = gen_reg_rtx (ptr_mode);
60790075Sobrien      fun->eh->exc_ptr = exc_ptr;
60850397Sobrien    }
60990075Sobrien  return exc_ptr;
61050397Sobrien}
61150397Sobrien
61290075Sobrien/* Return an rtl expression for the exception dispatch filter
61390075Sobrien   within a handler.  */
61450397Sobrien
615169689Skanrtx
616132718Skanget_exception_filter (struct function *fun)
61750397Sobrien{
61890075Sobrien  rtx filter = fun->eh->filter;
61990075Sobrien  if (fun == cfun && ! filter)
62050397Sobrien    {
621169689Skan      filter = gen_reg_rtx (targetm.eh_return_filter_mode ());
62290075Sobrien      fun->eh->filter = filter;
62350397Sobrien    }
62490075Sobrien  return filter;
62550397Sobrien}
62690075Sobrien
62790075Sobrien/* This section is for the exception handling specific optimization pass.  */
62850397Sobrien
629169689Skan/* Random access the exception region tree.  */
63090075Sobrien
631169689Skanvoid
632132718Skancollect_eh_region_array (void)
63350397Sobrien{
634169689Skan  struct eh_region *i;
63550397Sobrien
63690075Sobrien  i = cfun->eh->region_tree;
63790075Sobrien  if (! i)
63890075Sobrien    return;
63950397Sobrien
640169689Skan  VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
641169689Skan		 cfun->eh->last_region_number + 1);
642169689Skan  VEC_replace (eh_region, cfun->eh->region_array, 0, 0);
64350397Sobrien
64490075Sobrien  while (1)
64590075Sobrien    {
646169689Skan      VEC_replace (eh_region, cfun->eh->region_array, i->region_number, i);
64750397Sobrien
64890075Sobrien      /* If there are sub-regions, process them.  */
64990075Sobrien      if (i->inner)
65090075Sobrien	i = i->inner;
65190075Sobrien      /* If there are peers, process them.  */
65290075Sobrien      else if (i->next_peer)
65390075Sobrien	i = i->next_peer;
65490075Sobrien      /* Otherwise, step back up the tree to the next peer.  */
65590075Sobrien      else
65690075Sobrien	{
65790075Sobrien	  do {
65890075Sobrien	    i = i->outer;
65990075Sobrien	    if (i == NULL)
66090075Sobrien	      return;
66190075Sobrien	  } while (i->next_peer == NULL);
66290075Sobrien	  i = i->next_peer;
66390075Sobrien	}
66490075Sobrien    }
66590075Sobrien}
66650397Sobrien
66790075Sobrien/* Remove all regions whose labels are not reachable from insns.  */
66852284Sobrien
66990075Sobrienstatic void
670132718Skanremove_unreachable_regions (rtx insns)
67152284Sobrien{
67290075Sobrien  int i, *uid_region_num;
67390075Sobrien  bool *reachable;
67490075Sobrien  struct eh_region *r;
67590075Sobrien  rtx insn;
67652284Sobrien
67790075Sobrien  uid_region_num = xcalloc (get_max_uid (), sizeof(int));
67890075Sobrien  reachable = xcalloc (cfun->eh->last_region_number + 1, sizeof(bool));
67952284Sobrien
68090075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
68190075Sobrien    {
682169689Skan      r = VEC_index (eh_region, cfun->eh->region_array, i);
68390075Sobrien      if (!r || r->region_number != i)
68490075Sobrien	continue;
68552284Sobrien
68690075Sobrien      if (r->resume)
687117395Skan	{
688169689Skan	  gcc_assert (!uid_region_num[INSN_UID (r->resume)]);
68990075Sobrien	  uid_region_num[INSN_UID (r->resume)] = i;
690117395Skan	}
69190075Sobrien      if (r->label)
692117395Skan	{
693169689Skan	  gcc_assert (!uid_region_num[INSN_UID (r->label)]);
69490075Sobrien	  uid_region_num[INSN_UID (r->label)] = i;
695117395Skan	}
69652284Sobrien    }
69752284Sobrien
69890075Sobrien  for (insn = insns; insn; insn = NEXT_INSN (insn))
699169689Skan    reachable[uid_region_num[INSN_UID (insn)]] = true;
70050397Sobrien
70190075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
70250397Sobrien    {
703169689Skan      r = VEC_index (eh_region, cfun->eh->region_array, i);
70490075Sobrien      if (r && r->region_number == i && !reachable[i])
70550397Sobrien	{
706169689Skan	  bool kill_it = true;
707169689Skan	  switch (r->type)
70890075Sobrien	    {
709169689Skan	    case ERT_THROW:
710169689Skan	      /* Don't remove ERT_THROW regions if their outer region
711169689Skan		 is reachable.  */
712169689Skan	      if (r->outer && reachable[r->outer->region_number])
713169689Skan		kill_it = false;
714169689Skan	      break;
71550397Sobrien
716169689Skan	    case ERT_MUST_NOT_THROW:
717169689Skan	      /* MUST_NOT_THROW regions are implementable solely in the
718169689Skan		 runtime, but their existence continues to affect calls
719169689Skan		 within that region.  Never delete them here.  */
720169689Skan	      kill_it = false;
721169689Skan	      break;
72250397Sobrien
723169689Skan	    case ERT_TRY:
724169689Skan	      {
725169689Skan		/* TRY regions are reachable if any of its CATCH regions
726169689Skan		   are reachable.  */
727169689Skan		struct eh_region *c;
728169689Skan		for (c = r->u.try.catch; c ; c = c->u.catch.next_catch)
729169689Skan		  if (reachable[c->region_number])
73090075Sobrien		    {
731169689Skan		      kill_it = false;
732169689Skan		      break;
73390075Sobrien		    }
734169689Skan		break;
735169689Skan	      }
73650397Sobrien
737169689Skan	    default:
738169689Skan	      break;
73990075Sobrien	    }
74050397Sobrien
741169689Skan	  if (kill_it)
742169689Skan	    remove_eh_handler (r);
74390075Sobrien	}
74490075Sobrien    }
74550397Sobrien
746169689Skan  free (reachable);
747169689Skan  free (uid_region_num);
74850397Sobrien}
74950397Sobrien
750169689Skan/* Set up EH labels for RTL.  */
751169689Skan
75290075Sobrienvoid
753132718Skanconvert_from_eh_region_ranges (void)
75450397Sobrien{
755169689Skan  rtx insns = get_insns ();
756169689Skan  int i, n = cfun->eh->last_region_number;
75750397Sobrien
758169689Skan  /* Most of the work is already done at the tree level.  All we need to
759169689Skan     do is collect the rtl labels that correspond to the tree labels that
760169689Skan     collect the rtl labels that correspond to the tree labels
761169689Skan     we allocated earlier.  */
762169689Skan  for (i = 1; i <= n; ++i)
763169689Skan    {
764169689Skan      struct eh_region *region;
76550397Sobrien
766169689Skan      region = VEC_index (eh_region, cfun->eh->region_array, i);
767169689Skan      if (region && region->tree_label)
768169689Skan	region->label = DECL_RTL_IF_SET (region->tree_label);
769169689Skan    }
77050397Sobrien
77190075Sobrien  remove_unreachable_regions (insns);
77250397Sobrien}
77350397Sobrien
77496263Sobrienstatic void
775132718Skanadd_ehl_entry (rtx label, struct eh_region *region)
77696263Sobrien{
77796263Sobrien  struct ehl_map_entry **slot, *entry;
77896263Sobrien
77996263Sobrien  LABEL_PRESERVE_P (label) = 1;
78096263Sobrien
781132718Skan  entry = ggc_alloc (sizeof (*entry));
78296263Sobrien  entry->label = label;
78396263Sobrien  entry->region = region;
78496263Sobrien
78596263Sobrien  slot = (struct ehl_map_entry **)
786117395Skan    htab_find_slot (cfun->eh->exception_handler_label_map, entry, INSERT);
78796263Sobrien
78896263Sobrien  /* Before landing pad creation, each exception handler has its own
78996263Sobrien     label.  After landing pad creation, the exception handlers may
79096263Sobrien     share landing pads.  This is ok, since maybe_remove_eh_handler
79196263Sobrien     only requires the 1-1 mapping before landing pad creation.  */
792169689Skan  gcc_assert (!*slot || cfun->eh->built_landing_pads);
79396263Sobrien
79496263Sobrien  *slot = entry;
79596263Sobrien}
79696263Sobrien
79790075Sobrienvoid
798132718Skanfind_exception_handler_labels (void)
79990075Sobrien{
80090075Sobrien  int i;
80150397Sobrien
802117395Skan  if (cfun->eh->exception_handler_label_map)
803117395Skan    htab_empty (cfun->eh->exception_handler_label_map);
80496263Sobrien  else
80596263Sobrien    {
80696263Sobrien      /* ??? The expansion factor here (3/2) must be greater than the htab
80796263Sobrien	 occupancy factor (4/3) to avoid unnecessary resizing.  */
808117395Skan      cfun->eh->exception_handler_label_map
809117395Skan        = htab_create_ggc (cfun->eh->last_region_number * 3 / 2,
810117395Skan			   ehl_hash, ehl_eq, NULL);
81196263Sobrien    }
81250397Sobrien
81390075Sobrien  if (cfun->eh->region_tree == NULL)
81490075Sobrien    return;
81590075Sobrien
81690075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
81750397Sobrien    {
818169689Skan      struct eh_region *region;
81990075Sobrien      rtx lab;
82050397Sobrien
821169689Skan      region = VEC_index (eh_region, cfun->eh->region_array, i);
82290075Sobrien      if (! region || region->region_number != i)
82390075Sobrien	continue;
82490075Sobrien      if (cfun->eh->built_landing_pads)
82590075Sobrien	lab = region->landing_pad;
82690075Sobrien      else
82790075Sobrien	lab = region->label;
82850397Sobrien
82990075Sobrien      if (lab)
83096263Sobrien	add_ehl_entry (lab, region);
83150397Sobrien    }
83290075Sobrien
83390075Sobrien  /* For sjlj exceptions, need the return label to remain live until
83490075Sobrien     after landing pad generation.  */
83590075Sobrien  if (USING_SJLJ_EXCEPTIONS && ! cfun->eh->built_landing_pads)
83696263Sobrien    add_ehl_entry (return_label, NULL);
83796263Sobrien}
83890075Sobrien
839169689Skan/* Returns true if the current function has exception handling regions.  */
840169689Skan
84196263Sobrienbool
842132718Skancurrent_function_has_exception_handlers (void)
84396263Sobrien{
84496263Sobrien  int i;
84596263Sobrien
84696263Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
84796263Sobrien    {
848169689Skan      struct eh_region *region;
84996263Sobrien
850169689Skan      region = VEC_index (eh_region, cfun->eh->region_array, i);
851169689Skan      if (region
852169689Skan	  && region->region_number == i
853169689Skan	  && region->type != ERT_THROW)
85496263Sobrien	return true;
85596263Sobrien    }
85696263Sobrien
85796263Sobrien  return false;
85850397Sobrien}
85990075Sobrien
860169689Skan/* A subroutine of duplicate_eh_regions.  Search the region tree under O
861169689Skan   for the minimum and maximum region numbers.  Update *MIN and *MAX.  */
862169689Skan
863169689Skanstatic void
864169689Skanduplicate_eh_regions_0 (eh_region o, int *min, int *max)
86550397Sobrien{
866169689Skan  if (o->region_number < *min)
867169689Skan    *min = o->region_number;
868169689Skan  if (o->region_number > *max)
869169689Skan    *max = o->region_number;
87050397Sobrien
871169689Skan  if (o->inner)
87290075Sobrien    {
873169689Skan      o = o->inner;
874169689Skan      duplicate_eh_regions_0 (o, min, max);
875169689Skan      while (o->next_peer)
876169689Skan	{
877169689Skan	  o = o->next_peer;
878169689Skan	  duplicate_eh_regions_0 (o, min, max);
879169689Skan	}
880169689Skan    }
881169689Skan}
88250397Sobrien
883169689Skan/* A subroutine of duplicate_eh_regions.  Copy the region tree under OLD.
884169689Skan   Root it at OUTER, and apply EH_OFFSET to the region number.  Don't worry
885169689Skan   about the other internal pointers just yet, just the tree-like pointers.  */
88650397Sobrien
887169689Skanstatic eh_region
888169689Skanduplicate_eh_regions_1 (eh_region old, eh_region outer, int eh_offset)
889169689Skan{
890169689Skan  eh_region ret, n;
89150397Sobrien
892169689Skan  ret = n = ggc_alloc (sizeof (struct eh_region));
89350397Sobrien
894169689Skan  *n = *old;
895169689Skan  n->outer = outer;
896169689Skan  n->next_peer = NULL;
897169689Skan  gcc_assert (!old->aka);
89850397Sobrien
899169689Skan  n->region_number += eh_offset;
900169689Skan  VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n);
90150397Sobrien
902169689Skan  if (old->inner)
90390075Sobrien    {
904169689Skan      old = old->inner;
905169689Skan      n = n->inner = duplicate_eh_regions_1 (old, ret, eh_offset);
906169689Skan      while (old->next_peer)
907169689Skan	{
908169689Skan	  old = old->next_peer;
909169689Skan	  n = n->next_peer = duplicate_eh_regions_1 (old, ret, eh_offset);
910169689Skan	}
91190075Sobrien    }
91250397Sobrien
913169689Skan  return ret;
91450397Sobrien}
91550397Sobrien
916169689Skan/* Duplicate the EH regions of IFUN, rooted at COPY_REGION, into current
917169689Skan   function and root the tree below OUTER_REGION.  Remap labels using MAP
918169689Skan   callback.  The special case of COPY_REGION of 0 means all regions.  */
919169689Skan
920169689Skanint
921169689Skanduplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
922169689Skan		      void *data, int copy_region, int outer_region)
92350397Sobrien{
924169689Skan  eh_region cur, prev_try, outer, *splice;
925169689Skan  int i, min_region, max_region, eh_offset, cfun_last_region_number;
926169689Skan  int num_regions;
92750397Sobrien
928169689Skan  if (!ifun->eh->region_tree)
929169689Skan    return 0;
930169689Skan
931169689Skan  /* Find the range of region numbers to be copied.  The interface we
932169689Skan     provide here mandates a single offset to find new number from old,
933169689Skan     which means we must look at the numbers present, instead of the
934169689Skan     count or something else.  */
935169689Skan  if (copy_region > 0)
93690075Sobrien    {
937169689Skan      min_region = INT_MAX;
938169689Skan      max_region = 0;
93950397Sobrien
940169689Skan      cur = VEC_index (eh_region, ifun->eh->region_array, copy_region);
941169689Skan      duplicate_eh_regions_0 (cur, &min_region, &max_region);
94290075Sobrien    }
943169689Skan  else
944169689Skan    min_region = 1, max_region = ifun->eh->last_region_number;
945169689Skan  num_regions = max_region - min_region + 1;
946169689Skan  cfun_last_region_number = cfun->eh->last_region_number;
947169689Skan  eh_offset = cfun_last_region_number + 1 - min_region;
94890075Sobrien
949169689Skan  /* If we've not yet created a region array, do so now.  */
950169689Skan  VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
951169689Skan		 cfun_last_region_number + 1 + num_regions);
952169689Skan  cfun->eh->last_region_number = max_region + eh_offset;
95390075Sobrien
954169689Skan  /* We may have just allocated the array for the first time.
955169689Skan     Make sure that element zero is null.  */
956169689Skan  VEC_replace (eh_region, cfun->eh->region_array, 0, 0);
95750397Sobrien
958169689Skan  /* Zero all entries in the range allocated.  */
959169689Skan  memset (VEC_address (eh_region, cfun->eh->region_array)
960169689Skan	  + cfun_last_region_number + 1, 0, num_regions * sizeof (eh_region));
96150397Sobrien
962169689Skan  /* Locate the spot at which to insert the new tree.  */
963169689Skan  if (outer_region > 0)
964169689Skan    {
965169689Skan      outer = VEC_index (eh_region, cfun->eh->region_array, outer_region);
966169689Skan      splice = &outer->inner;
967169689Skan    }
968169689Skan  else
969169689Skan    {
970169689Skan      outer = NULL;
971169689Skan      splice = &cfun->eh->region_tree;
972169689Skan    }
973169689Skan  while (*splice)
974169689Skan    splice = &(*splice)->next_peer;
97550397Sobrien
976169689Skan  /* Copy all the regions in the subtree.  */
977169689Skan  if (copy_region > 0)
97890075Sobrien    {
979169689Skan      cur = VEC_index (eh_region, ifun->eh->region_array, copy_region);
980169689Skan      *splice = duplicate_eh_regions_1 (cur, outer, eh_offset);
98190075Sobrien    }
982169689Skan  else
98390075Sobrien    {
984169689Skan      eh_region n;
985169689Skan
986169689Skan      cur = ifun->eh->region_tree;
987169689Skan      *splice = n = duplicate_eh_regions_1 (cur, outer, eh_offset);
988169689Skan      while (cur->next_peer)
989169689Skan	{
990169689Skan	  cur = cur->next_peer;
991169689Skan	  n = n->next_peer = duplicate_eh_regions_1 (cur, outer, eh_offset);
992169689Skan	}
99390075Sobrien    }
99450397Sobrien
995169689Skan  /* Remap all the labels in the new regions.  */
996169689Skan  for (i = cfun_last_region_number + 1;
997169689Skan       VEC_iterate (eh_region, cfun->eh->region_array, i, cur); ++i)
998169689Skan    if (cur && cur->tree_label)
999169689Skan      cur->tree_label = map (cur->tree_label, data);
1000169689Skan
1001169689Skan  /* Search for the containing ERT_TRY region to fix up
1002169689Skan     the prev_try short-cuts for ERT_CLEANUP regions.  */
1003169689Skan  prev_try = NULL;
1004169689Skan  if (outer_region > 0)
1005169689Skan    for (prev_try = VEC_index (eh_region, cfun->eh->region_array, outer_region);
1006169689Skan         prev_try && prev_try->type != ERT_TRY;
1007169689Skan	 prev_try = prev_try->outer)
1008171825Skan      if (prev_try->type == ERT_MUST_NOT_THROW)
1009171825Skan	{
1010171825Skan	  prev_try = NULL;
1011171825Skan	  break;
1012171825Skan	}
1013169689Skan
1014169689Skan  /* Remap all of the internal catch and cleanup linkages.  Since we
1015169689Skan     duplicate entire subtrees, all of the referenced regions will have
1016169689Skan     been copied too.  And since we renumbered them as a block, a simple
1017169689Skan     bit of arithmetic finds us the index for the replacement region.  */
1018169689Skan  for (i = cfun_last_region_number + 1;
1019169689Skan       VEC_iterate (eh_region, cfun->eh->region_array, i, cur); ++i)
102090075Sobrien    {
1021169689Skan      if (cur == NULL)
1022169689Skan	continue;
1023169689Skan
1024169689Skan#define REMAP(REG) \
1025169689Skan	(REG) = VEC_index (eh_region, cfun->eh->region_array, \
1026169689Skan			   (REG)->region_number + eh_offset)
1027169689Skan
1028169689Skan      switch (cur->type)
102990075Sobrien	{
1030169689Skan	case ERT_TRY:
1031169689Skan	  if (cur->u.try.catch)
1032169689Skan	    REMAP (cur->u.try.catch);
1033169689Skan	  if (cur->u.try.last_catch)
1034169689Skan	    REMAP (cur->u.try.last_catch);
1035169689Skan	  break;
1036169689Skan
1037169689Skan	case ERT_CATCH:
1038169689Skan	  if (cur->u.catch.next_catch)
1039169689Skan	    REMAP (cur->u.catch.next_catch);
1040169689Skan	  if (cur->u.catch.prev_catch)
1041169689Skan	    REMAP (cur->u.catch.prev_catch);
1042169689Skan	  break;
1043169689Skan
1044169689Skan	case ERT_CLEANUP:
1045169689Skan	  if (cur->u.cleanup.prev_try)
1046169689Skan	    REMAP (cur->u.cleanup.prev_try);
1047169689Skan	  else
1048169689Skan	    cur->u.cleanup.prev_try = prev_try;
1049169689Skan	  break;
1050169689Skan
1051169689Skan	default:
1052169689Skan	  break;
105390075Sobrien	}
105450397Sobrien
1055169689Skan#undef REMAP
105690075Sobrien    }
1057169689Skan
1058169689Skan  return eh_offset;
1059169689Skan}
1060169689Skan
1061169689Skan/* Return true if REGION_A is outer to REGION_B in IFUN.  */
1062169689Skan
1063169689Skanbool
1064169689Skaneh_region_outer_p (struct function *ifun, int region_a, int region_b)
1065169689Skan{
1066169689Skan  struct eh_region *rp_a, *rp_b;
1067169689Skan
1068169689Skan  gcc_assert (ifun->eh->last_region_number > 0);
1069169689Skan  gcc_assert (ifun->eh->region_tree);
1070169689Skan
1071169689Skan  rp_a = VEC_index (eh_region, ifun->eh->region_array, region_a);
1072169689Skan  rp_b = VEC_index (eh_region, ifun->eh->region_array, region_b);
1073169689Skan  gcc_assert (rp_a != NULL);
1074169689Skan  gcc_assert (rp_b != NULL);
1075169689Skan
1076169689Skan  do
107790075Sobrien    {
1078169689Skan      if (rp_a == rp_b)
1079169689Skan	return true;
1080169689Skan      rp_b = rp_b->outer;
1081169689Skan    }
1082169689Skan  while (rp_b);
1083169689Skan
1084169689Skan  return false;
1085169689Skan}
1086169689Skan
1087169689Skan/* Return region number of region that is outer to both if REGION_A and
1088169689Skan   REGION_B in IFUN.  */
1089169689Skan
1090169689Skanint
1091169689Skaneh_region_outermost (struct function *ifun, int region_a, int region_b)
1092169689Skan{
1093169689Skan  struct eh_region *rp_a, *rp_b;
1094169689Skan  sbitmap b_outer;
1095169689Skan
1096169689Skan  gcc_assert (ifun->eh->last_region_number > 0);
1097169689Skan  gcc_assert (ifun->eh->region_tree);
1098169689Skan
1099169689Skan  rp_a = VEC_index (eh_region, ifun->eh->region_array, region_a);
1100169689Skan  rp_b = VEC_index (eh_region, ifun->eh->region_array, region_b);
1101169689Skan  gcc_assert (rp_a != NULL);
1102169689Skan  gcc_assert (rp_b != NULL);
1103169689Skan
1104169689Skan  b_outer = sbitmap_alloc (ifun->eh->last_region_number + 1);
1105169689Skan  sbitmap_zero (b_outer);
1106169689Skan
1107169689Skan  do
1108169689Skan    {
1109169689Skan      SET_BIT (b_outer, rp_b->region_number);
1110169689Skan      rp_b = rp_b->outer;
1111169689Skan    }
1112169689Skan  while (rp_b);
1113169689Skan
1114169689Skan  do
1115169689Skan    {
1116169689Skan      if (TEST_BIT (b_outer, rp_a->region_number))
111790075Sobrien	{
1118169689Skan	  sbitmap_free (b_outer);
1119169689Skan	  return rp_a->region_number;
112090075Sobrien	}
1121169689Skan      rp_a = rp_a->outer;
112290075Sobrien    }
1123169689Skan  while (rp_a);
112450397Sobrien
1125169689Skan  sbitmap_free (b_outer);
1126169689Skan  return -1;
112790075Sobrien}
112890075Sobrien
112990075Sobrienstatic int
1130132718Skant2r_eq (const void *pentry, const void *pdata)
113190075Sobrien{
113290075Sobrien  tree entry = (tree) pentry;
113390075Sobrien  tree data = (tree) pdata;
113450397Sobrien
113590075Sobrien  return TREE_PURPOSE (entry) == data;
113690075Sobrien}
113750397Sobrien
113890075Sobrienstatic hashval_t
1139132718Skant2r_hash (const void *pentry)
114090075Sobrien{
114190075Sobrien  tree entry = (tree) pentry;
1142169689Skan  return TREE_HASH (TREE_PURPOSE (entry));
114350397Sobrien}
114450397Sobrien
114550397Sobrienstatic void
1146132718Skanadd_type_for_runtime (tree type)
114790075Sobrien{
114890075Sobrien  tree *slot;
114950397Sobrien
115090075Sobrien  slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
1151169689Skan					    TREE_HASH (type), INSERT);
115290075Sobrien  if (*slot == NULL)
115390075Sobrien    {
115490075Sobrien      tree runtime = (*lang_eh_runtime_type) (type);
115590075Sobrien      *slot = tree_cons (type, runtime, NULL_TREE);
115690075Sobrien    }
115790075Sobrien}
115850397Sobrien
115990075Sobrienstatic tree
1160132718Skanlookup_type_for_runtime (tree type)
116190075Sobrien{
116290075Sobrien  tree *slot;
116350397Sobrien
116490075Sobrien  slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
1165169689Skan					    TREE_HASH (type), NO_INSERT);
116650397Sobrien
116790075Sobrien  /* We should have always inserted the data earlier.  */
116890075Sobrien  return TREE_VALUE (*slot);
116990075Sobrien}
117050397Sobrien
117190075Sobrien
117290075Sobrien/* Represent an entry in @TTypes for either catch actions
117390075Sobrien   or exception filter actions.  */
1174117395Skanstruct ttypes_filter GTY(())
117590075Sobrien{
117690075Sobrien  tree t;
117790075Sobrien  int filter;
117890075Sobrien};
117950397Sobrien
118090075Sobrien/* Compare ENTRY (a ttypes_filter entry in the hash table) with DATA
118190075Sobrien   (a tree) for a @TTypes type node we are thinking about adding.  */
118250397Sobrien
118390075Sobrienstatic int
1184132718Skanttypes_filter_eq (const void *pentry, const void *pdata)
118590075Sobrien{
118690075Sobrien  const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
118790075Sobrien  tree data = (tree) pdata;
118850397Sobrien
118990075Sobrien  return entry->t == data;
119050397Sobrien}
119150397Sobrien
119290075Sobrienstatic hashval_t
1193132718Skanttypes_filter_hash (const void *pentry)
119490075Sobrien{
119590075Sobrien  const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
1196169689Skan  return TREE_HASH (entry->t);
119790075Sobrien}
119850397Sobrien
119990075Sobrien/* Compare ENTRY with DATA (both struct ttypes_filter) for a @TTypes
120090075Sobrien   exception specification list we are thinking about adding.  */
120190075Sobrien/* ??? Currently we use the type lists in the order given.  Someone
120290075Sobrien   should put these in some canonical order.  */
120350397Sobrien
120490075Sobrienstatic int
1205132718Skanehspec_filter_eq (const void *pentry, const void *pdata)
120650397Sobrien{
120790075Sobrien  const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
120890075Sobrien  const struct ttypes_filter *data = (const struct ttypes_filter *) pdata;
120950397Sobrien
121090075Sobrien  return type_list_equal (entry->t, data->t);
121190075Sobrien}
121250397Sobrien
121390075Sobrien/* Hash function for exception specification lists.  */
121450397Sobrien
121590075Sobrienstatic hashval_t
1216132718Skanehspec_filter_hash (const void *pentry)
121790075Sobrien{
121890075Sobrien  const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
121990075Sobrien  hashval_t h = 0;
122090075Sobrien  tree list;
122150397Sobrien
122290075Sobrien  for (list = entry->t; list ; list = TREE_CHAIN (list))
1223169689Skan    h = (h << 5) + (h >> 27) + TREE_HASH (TREE_VALUE (list));
122490075Sobrien  return h;
122550397Sobrien}
122650397Sobrien
1227169689Skan/* Add TYPE (which may be NULL) to cfun->eh->ttype_data, using TYPES_HASH
1228169689Skan   to speed up the search.  Return the filter value to be used.  */
122950397Sobrien
123090075Sobrienstatic int
1231132718Skanadd_ttypes_entry (htab_t ttypes_hash, tree type)
123250397Sobrien{
123390075Sobrien  struct ttypes_filter **slot, *n;
123450397Sobrien
123590075Sobrien  slot = (struct ttypes_filter **)
1236169689Skan    htab_find_slot_with_hash (ttypes_hash, type, TREE_HASH (type), INSERT);
123750397Sobrien
123890075Sobrien  if ((n = *slot) == NULL)
123950397Sobrien    {
124090075Sobrien      /* Filter value is a 1 based table index.  */
124150397Sobrien
1242169689Skan      n = XNEW (struct ttypes_filter);
124390075Sobrien      n->t = type;
1244169689Skan      n->filter = VEC_length (tree, cfun->eh->ttype_data) + 1;
124590075Sobrien      *slot = n;
124650397Sobrien
1247169689Skan      VEC_safe_push (tree, gc, cfun->eh->ttype_data, type);
124850397Sobrien    }
124950397Sobrien
125090075Sobrien  return n->filter;
125150397Sobrien}
125250397Sobrien
125390075Sobrien/* Add LIST to cfun->eh->ehspec_data, using EHSPEC_HASH and TYPES_HASH
125490075Sobrien   to speed up the search.  Return the filter value to be used.  */
125550397Sobrien
125690075Sobrienstatic int
1257132718Skanadd_ehspec_entry (htab_t ehspec_hash, htab_t ttypes_hash, tree list)
125850397Sobrien{
125990075Sobrien  struct ttypes_filter **slot, *n;
126090075Sobrien  struct ttypes_filter dummy;
126150397Sobrien
126290075Sobrien  dummy.t = list;
126390075Sobrien  slot = (struct ttypes_filter **)
126490075Sobrien    htab_find_slot (ehspec_hash, &dummy, INSERT);
126550397Sobrien
126690075Sobrien  if ((n = *slot) == NULL)
126790075Sobrien    {
126890075Sobrien      /* Filter value is a -1 based byte index into a uleb128 buffer.  */
126950397Sobrien
1270169689Skan      n = XNEW (struct ttypes_filter);
127190075Sobrien      n->t = list;
127290075Sobrien      n->filter = -(VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) + 1);
127390075Sobrien      *slot = n;
127450397Sobrien
1275169689Skan      /* Generate a 0 terminated list of filter values.  */
127690075Sobrien      for (; list ; list = TREE_CHAIN (list))
1277169689Skan	{
1278169689Skan	  if (targetm.arm_eabi_unwinder)
1279169689Skan	    VARRAY_PUSH_TREE (cfun->eh->ehspec_data, TREE_VALUE (list));
1280169689Skan	  else
1281169689Skan	    {
1282169689Skan	      /* Look up each type in the list and encode its filter
1283169689Skan		 value as a uleb128.  */
1284169689Skan	      push_uleb128 (&cfun->eh->ehspec_data,
1285169689Skan		  add_ttypes_entry (ttypes_hash, TREE_VALUE (list)));
1286169689Skan	    }
1287169689Skan	}
1288169689Skan      if (targetm.arm_eabi_unwinder)
1289169689Skan	VARRAY_PUSH_TREE (cfun->eh->ehspec_data, NULL_TREE);
1290169689Skan      else
1291169689Skan	VARRAY_PUSH_UCHAR (cfun->eh->ehspec_data, 0);
129290075Sobrien    }
129390075Sobrien
129490075Sobrien  return n->filter;
129590075Sobrien}
129690075Sobrien
129790075Sobrien/* Generate the action filter values to be used for CATCH and
129890075Sobrien   ALLOWED_EXCEPTIONS regions.  When using dwarf2 exception regions,
129990075Sobrien   we use lots of landing pads, and so every type or list can share
130090075Sobrien   the same filter value, which saves table space.  */
130190075Sobrien
130290075Sobrienstatic void
1303132718Skanassign_filter_values (void)
130450397Sobrien{
130590075Sobrien  int i;
130690075Sobrien  htab_t ttypes, ehspec;
130750397Sobrien
1308169689Skan  cfun->eh->ttype_data = VEC_alloc (tree, gc, 16);
1309169689Skan  if (targetm.arm_eabi_unwinder)
1310169689Skan    VARRAY_TREE_INIT (cfun->eh->ehspec_data, 64, "ehspec_data");
1311169689Skan  else
1312169689Skan    VARRAY_UCHAR_INIT (cfun->eh->ehspec_data, 64, "ehspec_data");
131350397Sobrien
131490075Sobrien  ttypes = htab_create (31, ttypes_filter_hash, ttypes_filter_eq, free);
131590075Sobrien  ehspec = htab_create (31, ehspec_filter_hash, ehspec_filter_eq, free);
131650397Sobrien
131790075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
131850397Sobrien    {
1319169689Skan      struct eh_region *r;
132050397Sobrien
1321169689Skan      r = VEC_index (eh_region, cfun->eh->region_array, i);
1322169689Skan
132390075Sobrien      /* Mind we don't process a region more than once.  */
132490075Sobrien      if (!r || r->region_number != i)
132590075Sobrien	continue;
132650397Sobrien
132790075Sobrien      switch (r->type)
132890075Sobrien	{
132990075Sobrien	case ERT_CATCH:
133090075Sobrien	  /* Whatever type_list is (NULL or true list), we build a list
133190075Sobrien	     of filters for the region.  */
133290075Sobrien	  r->u.catch.filter_list = NULL_TREE;
133350397Sobrien
133490075Sobrien	  if (r->u.catch.type_list != NULL)
133590075Sobrien	    {
133690075Sobrien	      /* Get a filter value for each of the types caught and store
133790075Sobrien		 them in the region's dedicated list.  */
133890075Sobrien	      tree tp_node = r->u.catch.type_list;
133950397Sobrien
134090075Sobrien	      for (;tp_node; tp_node = TREE_CHAIN (tp_node))
134190075Sobrien		{
134290075Sobrien		  int flt = add_ttypes_entry (ttypes, TREE_VALUE (tp_node));
1343169689Skan		  tree flt_node = build_int_cst (NULL_TREE, flt);
134450397Sobrien
134590075Sobrien		  r->u.catch.filter_list
134690075Sobrien		    = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list);
134790075Sobrien		}
134890075Sobrien	    }
134990075Sobrien	  else
135090075Sobrien	    {
135190075Sobrien	      /* Get a filter value for the NULL list also since it will need
135290075Sobrien		 an action record anyway.  */
135390075Sobrien	      int flt = add_ttypes_entry (ttypes, NULL);
1354169689Skan	      tree flt_node = build_int_cst (NULL_TREE, flt);
135550397Sobrien
135690075Sobrien	      r->u.catch.filter_list
135790075Sobrien		= tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list);
135890075Sobrien	    }
135950397Sobrien
136090075Sobrien	  break;
136150397Sobrien
136290075Sobrien	case ERT_ALLOWED_EXCEPTIONS:
136390075Sobrien	  r->u.allowed.filter
136490075Sobrien	    = add_ehspec_entry (ehspec, ttypes, r->u.allowed.type_list);
136590075Sobrien	  break;
136650397Sobrien
136790075Sobrien	default:
136890075Sobrien	  break;
136990075Sobrien	}
137050397Sobrien    }
137190075Sobrien
137290075Sobrien  htab_delete (ttypes);
137390075Sobrien  htab_delete (ehspec);
137450397Sobrien}
137550397Sobrien
1376169689Skan/* Emit SEQ into basic block just before INSN (that is assumed to be
1377169689Skan   first instruction of some existing BB and return the newly
1378169689Skan   produced block.  */
1379169689Skanstatic basic_block
1380169689Skanemit_to_new_bb_before (rtx seq, rtx insn)
1381169689Skan{
1382169689Skan  rtx last;
1383169689Skan  basic_block bb;
1384169689Skan  edge e;
1385169689Skan  edge_iterator ei;
1386169689Skan
1387169689Skan  /* If there happens to be a fallthru edge (possibly created by cleanup_cfg
1388169689Skan     call), we don't want it to go into newly created landing pad or other EH
1389169689Skan     construct.  */
1390169689Skan  for (ei = ei_start (BLOCK_FOR_INSN (insn)->preds); (e = ei_safe_edge (ei)); )
1391169689Skan    if (e->flags & EDGE_FALLTHRU)
1392169689Skan      force_nonfallthru (e);
1393169689Skan    else
1394169689Skan      ei_next (&ei);
1395169689Skan  last = emit_insn_before (seq, insn);
1396169689Skan  if (BARRIER_P (last))
1397169689Skan    last = PREV_INSN (last);
1398169689Skan  bb = create_basic_block (seq, last, BLOCK_FOR_INSN (insn)->prev_bb);
1399169689Skan  update_bb_for_insn (bb);
1400169689Skan  bb->flags |= BB_SUPERBLOCK;
1401169689Skan  return bb;
1402169689Skan}
1403169689Skan
1404132718Skan/* Generate the code to actually handle exceptions, which will follow the
1405132718Skan   landing pads.  */
1406132718Skan
140790075Sobrienstatic void
1408132718Skanbuild_post_landing_pads (void)
140950397Sobrien{
141090075Sobrien  int i;
141150397Sobrien
141290075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
141390075Sobrien    {
1414169689Skan      struct eh_region *region;
141590075Sobrien      rtx seq;
141650397Sobrien
1417169689Skan      region = VEC_index (eh_region, cfun->eh->region_array, i);
141890075Sobrien      /* Mind we don't process a region more than once.  */
141990075Sobrien      if (!region || region->region_number != i)
142090075Sobrien	continue;
142150397Sobrien
142290075Sobrien      switch (region->type)
142390075Sobrien	{
142490075Sobrien	case ERT_TRY:
142590075Sobrien	  /* ??? Collect the set of all non-overlapping catch handlers
142690075Sobrien	       all the way up the chain until blocked by a cleanup.  */
142790075Sobrien	  /* ??? Outer try regions can share landing pads with inner
142890075Sobrien	     try regions if the types are completely non-overlapping,
142990075Sobrien	     and there are no intervening cleanups.  */
143050397Sobrien
143190075Sobrien	  region->post_landing_pad = gen_label_rtx ();
143250397Sobrien
143390075Sobrien	  start_sequence ();
143450397Sobrien
143590075Sobrien	  emit_label (region->post_landing_pad);
143650397Sobrien
143790075Sobrien	  /* ??? It is mighty inconvenient to call back into the
143890075Sobrien	     switch statement generation code in expand_end_case.
143990075Sobrien	     Rapid prototyping sez a sequence of ifs.  */
144090075Sobrien	  {
144190075Sobrien	    struct eh_region *c;
144290075Sobrien	    for (c = region->u.try.catch; c ; c = c->u.catch.next_catch)
144390075Sobrien	      {
144490075Sobrien		if (c->u.catch.type_list == NULL)
144590075Sobrien		  emit_jump (c->label);
144690075Sobrien		else
144790075Sobrien		  {
144890075Sobrien		    /* Need for one cmp/jump per type caught. Each type
144990075Sobrien		       list entry has a matching entry in the filter list
145090075Sobrien		       (see assign_filter_values).  */
145190075Sobrien		    tree tp_node = c->u.catch.type_list;
145290075Sobrien		    tree flt_node = c->u.catch.filter_list;
145350397Sobrien
145490075Sobrien		    for (; tp_node; )
145590075Sobrien		      {
145690075Sobrien			emit_cmp_and_jump_insns
145790075Sobrien			  (cfun->eh->filter,
145890075Sobrien			   GEN_INT (tree_low_cst (TREE_VALUE (flt_node), 0)),
1459169689Skan			   EQ, NULL_RTX,
1460169689Skan			   targetm.eh_return_filter_mode (), 0, c->label);
146150397Sobrien
146290075Sobrien			tp_node = TREE_CHAIN (tp_node);
146390075Sobrien			flt_node = TREE_CHAIN (flt_node);
146490075Sobrien		      }
146590075Sobrien		  }
146690075Sobrien	      }
146790075Sobrien	  }
146850397Sobrien
146990075Sobrien	  /* We delay the generation of the _Unwind_Resume until we generate
147090075Sobrien	     landing pads.  We emit a marker here so as to get good control
147190075Sobrien	     flow data in the meantime.  */
147290075Sobrien	  region->resume
147390075Sobrien	    = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
147490075Sobrien	  emit_barrier ();
147550397Sobrien
147690075Sobrien	  seq = get_insns ();
147790075Sobrien	  end_sequence ();
147850397Sobrien
1479169689Skan	  emit_to_new_bb_before (seq, region->u.try.catch->label);
1480169689Skan
148190075Sobrien	  break;
148250397Sobrien
148390075Sobrien	case ERT_ALLOWED_EXCEPTIONS:
148490075Sobrien	  region->post_landing_pad = gen_label_rtx ();
148550397Sobrien
148690075Sobrien	  start_sequence ();
148750397Sobrien
148890075Sobrien	  emit_label (region->post_landing_pad);
148950397Sobrien
149090075Sobrien	  emit_cmp_and_jump_insns (cfun->eh->filter,
149190075Sobrien				   GEN_INT (region->u.allowed.filter),
1492169689Skan				   EQ, NULL_RTX,
1493169689Skan				   targetm.eh_return_filter_mode (), 0, region->label);
149450397Sobrien
149590075Sobrien	  /* We delay the generation of the _Unwind_Resume until we generate
149690075Sobrien	     landing pads.  We emit a marker here so as to get good control
149790075Sobrien	     flow data in the meantime.  */
149890075Sobrien	  region->resume
149990075Sobrien	    = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
150090075Sobrien	  emit_barrier ();
150150397Sobrien
150290075Sobrien	  seq = get_insns ();
150390075Sobrien	  end_sequence ();
150490075Sobrien
1505169689Skan	  emit_to_new_bb_before (seq, region->label);
150690075Sobrien	  break;
150790075Sobrien
150890075Sobrien	case ERT_CLEANUP:
150990075Sobrien	case ERT_MUST_NOT_THROW:
151090075Sobrien	  region->post_landing_pad = region->label;
151190075Sobrien	  break;
151290075Sobrien
151390075Sobrien	case ERT_CATCH:
151490075Sobrien	case ERT_THROW:
151590075Sobrien	  /* Nothing to do.  */
151690075Sobrien	  break;
151790075Sobrien
151890075Sobrien	default:
1519169689Skan	  gcc_unreachable ();
152090075Sobrien	}
152190075Sobrien    }
152250397Sobrien}
152350397Sobrien
152490075Sobrien/* Replace RESX patterns with jumps to the next handler if any, or calls to
152590075Sobrien   _Unwind_Resume otherwise.  */
152650397Sobrien
152790075Sobrienstatic void
1528132718Skanconnect_post_landing_pads (void)
152950397Sobrien{
153090075Sobrien  int i;
153150397Sobrien
153290075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
153350397Sobrien    {
1534169689Skan      struct eh_region *region;
153590075Sobrien      struct eh_region *outer;
153690075Sobrien      rtx seq;
1537169689Skan      rtx barrier;
153850397Sobrien
1539169689Skan      region = VEC_index (eh_region, cfun->eh->region_array, i);
154090075Sobrien      /* Mind we don't process a region more than once.  */
154190075Sobrien      if (!region || region->region_number != i)
154290075Sobrien	continue;
154350397Sobrien
154490075Sobrien      /* If there is no RESX, or it has been deleted by flow, there's
154590075Sobrien	 nothing to fix up.  */
154690075Sobrien      if (! region->resume || INSN_DELETED_P (region->resume))
154790075Sobrien	continue;
154850397Sobrien
154990075Sobrien      /* Search for another landing pad in this function.  */
155090075Sobrien      for (outer = region->outer; outer ; outer = outer->outer)
155190075Sobrien	if (outer->post_landing_pad)
155290075Sobrien	  break;
155350397Sobrien
155490075Sobrien      start_sequence ();
155550397Sobrien
155690075Sobrien      if (outer)
1557169689Skan	{
1558169689Skan	  edge e;
1559169689Skan	  basic_block src, dest;
1560169689Skan
1561169689Skan	  emit_jump (outer->post_landing_pad);
1562169689Skan	  src = BLOCK_FOR_INSN (region->resume);
1563169689Skan	  dest = BLOCK_FOR_INSN (outer->post_landing_pad);
1564169689Skan	  while (EDGE_COUNT (src->succs) > 0)
1565169689Skan	    remove_edge (EDGE_SUCC (src, 0));
1566169689Skan	  e = make_edge (src, dest, 0);
1567169689Skan	  e->probability = REG_BR_PROB_BASE;
1568169689Skan	  e->count = src->count;
1569169689Skan	}
157090075Sobrien      else
1571169689Skan	{
1572169689Skan	  emit_library_call (unwind_resume_libfunc, LCT_THROW,
1573169689Skan			     VOIDmode, 1, cfun->eh->exc_ptr, ptr_mode);
157450397Sobrien
1575169689Skan	  /* What we just emitted was a throwing libcall, so it got a
1576169689Skan	     barrier automatically added after it.  If the last insn in
1577169689Skan	     the libcall sequence isn't the barrier, it's because the
1578169689Skan	     target emits multiple insns for a call, and there are insns
1579169689Skan	     after the actual call insn (which are redundant and would be
1580169689Skan	     optimized away).  The barrier is inserted exactly after the
1581169689Skan	     call insn, so let's go get that and delete the insns after
1582169689Skan	     it, because below we need the barrier to be the last insn in
1583169689Skan	     the sequence.  */
1584169689Skan	  delete_insns_since (NEXT_INSN (last_call_insn ()));
1585169689Skan	}
1586169689Skan
158790075Sobrien      seq = get_insns ();
158890075Sobrien      end_sequence ();
1589169689Skan      barrier = emit_insn_before (seq, region->resume);
1590169689Skan      /* Avoid duplicate barrier.  */
1591169689Skan      gcc_assert (BARRIER_P (barrier));
1592169689Skan      delete_insn (barrier);
159390075Sobrien      delete_insn (region->resume);
1594169689Skan
1595169689Skan      /* ??? From tree-ssa we can wind up with catch regions whose
1596169689Skan	 label is not instantiated, but whose resx is present.  Now
1597169689Skan	 that we've dealt with the resx, kill the region.  */
1598169689Skan      if (region->label == NULL && region->type == ERT_CLEANUP)
1599169689Skan	remove_eh_handler (region);
160050397Sobrien    }
160150397Sobrien}
160250397Sobrien
160390075Sobrien
160490075Sobrienstatic void
1605132718Skandw2_build_landing_pads (void)
160650397Sobrien{
160790075Sobrien  int i;
160850397Sobrien
160990075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
161090075Sobrien    {
1611169689Skan      struct eh_region *region;
161290075Sobrien      rtx seq;
1613169689Skan      basic_block bb;
1614169689Skan      edge e;
161550397Sobrien
1616169689Skan      region = VEC_index (eh_region, cfun->eh->region_array, i);
161790075Sobrien      /* Mind we don't process a region more than once.  */
161890075Sobrien      if (!region || region->region_number != i)
161990075Sobrien	continue;
162050397Sobrien
162190075Sobrien      if (region->type != ERT_CLEANUP
162290075Sobrien	  && region->type != ERT_TRY
162390075Sobrien	  && region->type != ERT_ALLOWED_EXCEPTIONS)
162490075Sobrien	continue;
162550397Sobrien
162690075Sobrien      start_sequence ();
162750397Sobrien
162890075Sobrien      region->landing_pad = gen_label_rtx ();
162990075Sobrien      emit_label (region->landing_pad);
163050397Sobrien
163190075Sobrien#ifdef HAVE_exception_receiver
163290075Sobrien      if (HAVE_exception_receiver)
163390075Sobrien	emit_insn (gen_exception_receiver ());
163490075Sobrien      else
163590075Sobrien#endif
163690075Sobrien#ifdef HAVE_nonlocal_goto_receiver
163790075Sobrien	if (HAVE_nonlocal_goto_receiver)
163890075Sobrien	  emit_insn (gen_nonlocal_goto_receiver ());
163990075Sobrien	else
164090075Sobrien#endif
164190075Sobrien	  { /* Nothing */ }
164250397Sobrien
164390075Sobrien      emit_move_insn (cfun->eh->exc_ptr,
1644117395Skan		      gen_rtx_REG (ptr_mode, EH_RETURN_DATA_REGNO (0)));
164590075Sobrien      emit_move_insn (cfun->eh->filter,
1646169689Skan		      gen_rtx_REG (targetm.eh_return_filter_mode (),
1647169689Skan				   EH_RETURN_DATA_REGNO (1)));
164852284Sobrien
164990075Sobrien      seq = get_insns ();
165090075Sobrien      end_sequence ();
165152284Sobrien
1652169689Skan      bb = emit_to_new_bb_before (seq, region->post_landing_pad);
1653169689Skan      e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
1654169689Skan      e->count = bb->count;
1655169689Skan      e->probability = REG_BR_PROB_BASE;
165652284Sobrien    }
165750397Sobrien}
165850397Sobrien
165990075Sobrien
166090075Sobrienstruct sjlj_lp_info
166190075Sobrien{
166290075Sobrien  int directly_reachable;
166390075Sobrien  int action_index;
166490075Sobrien  int dispatch_index;
166590075Sobrien  int call_site_index;
166690075Sobrien};
166752284Sobrien
166890075Sobrienstatic bool
1669132718Skansjlj_find_directly_reachable_regions (struct sjlj_lp_info *lp_info)
167052284Sobrien{
167190075Sobrien  rtx insn;
167290075Sobrien  bool found_one = false;
167352284Sobrien
167490075Sobrien  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
167552284Sobrien    {
167690075Sobrien      struct eh_region *region;
167790075Sobrien      enum reachable_code rc;
167890075Sobrien      tree type_thrown;
167990075Sobrien      rtx note;
168090075Sobrien
168190075Sobrien      if (! INSN_P (insn))
168290075Sobrien	continue;
168390075Sobrien
168490075Sobrien      note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
168590075Sobrien      if (!note || INTVAL (XEXP (note, 0)) <= 0)
168690075Sobrien	continue;
168790075Sobrien
1688169689Skan      region = VEC_index (eh_region, cfun->eh->region_array, INTVAL (XEXP (note, 0)));
168990075Sobrien
169090075Sobrien      type_thrown = NULL_TREE;
169190075Sobrien      if (region->type == ERT_THROW)
169290075Sobrien	{
169390075Sobrien	  type_thrown = region->u.throw.type;
169490075Sobrien	  region = region->outer;
169590075Sobrien	}
169690075Sobrien
169790075Sobrien      /* Find the first containing region that might handle the exception.
169890075Sobrien	 That's the landing pad to which we will transfer control.  */
169990075Sobrien      rc = RNL_NOT_CAUGHT;
170090075Sobrien      for (; region; region = region->outer)
170190075Sobrien	{
1702169689Skan	  rc = reachable_next_level (region, type_thrown, NULL);
170390075Sobrien	  if (rc != RNL_NOT_CAUGHT)
170490075Sobrien	    break;
170590075Sobrien	}
170690075Sobrien      if (rc == RNL_MAYBE_CAUGHT || rc == RNL_CAUGHT)
170790075Sobrien	{
170890075Sobrien	  lp_info[region->region_number].directly_reachable = 1;
170990075Sobrien	  found_one = true;
171090075Sobrien	}
171152284Sobrien    }
171252284Sobrien
171390075Sobrien  return found_one;
171452284Sobrien}
171552284Sobrien
171690075Sobrienstatic void
1717132718Skansjlj_assign_call_site_values (rtx dispatch_label, struct sjlj_lp_info *lp_info)
171890075Sobrien{
171990075Sobrien  htab_t ar_hash;
172090075Sobrien  int i, index;
172150397Sobrien
172290075Sobrien  /* First task: build the action table.  */
172350397Sobrien
172490075Sobrien  VARRAY_UCHAR_INIT (cfun->eh->action_record_data, 64, "action_record_data");
172590075Sobrien  ar_hash = htab_create (31, action_record_hash, action_record_eq, free);
172650397Sobrien
172790075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
172890075Sobrien    if (lp_info[i].directly_reachable)
172990075Sobrien      {
1730169689Skan	struct eh_region *r = VEC_index (eh_region, cfun->eh->region_array, i);
1731169689Skan
173290075Sobrien	r->landing_pad = dispatch_label;
173390075Sobrien	lp_info[i].action_index = collect_one_action_chain (ar_hash, r);
173490075Sobrien	if (lp_info[i].action_index != -1)
173590075Sobrien	  cfun->uses_eh_lsda = 1;
173690075Sobrien      }
173750397Sobrien
173890075Sobrien  htab_delete (ar_hash);
173950397Sobrien
174090075Sobrien  /* Next: assign dispatch values.  In dwarf2 terms, this would be the
174190075Sobrien     landing pad label for the region.  For sjlj though, there is one
174290075Sobrien     common landing pad from which we dispatch to the post-landing pads.
174350397Sobrien
174490075Sobrien     A region receives a dispatch index if it is directly reachable
174590075Sobrien     and requires in-function processing.  Regions that share post-landing
174690075Sobrien     pads may share dispatch indices.  */
174790075Sobrien  /* ??? Post-landing pad sharing doesn't actually happen at the moment
174890075Sobrien     (see build_post_landing_pads) so we don't bother checking for it.  */
174950397Sobrien
175090075Sobrien  index = 0;
175190075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
175290075Sobrien    if (lp_info[i].directly_reachable)
175390075Sobrien      lp_info[i].dispatch_index = index++;
175450397Sobrien
175590075Sobrien  /* Finally: assign call-site values.  If dwarf2 terms, this would be
175690075Sobrien     the region number assigned by convert_to_eh_region_ranges, but
175790075Sobrien     handles no-action and must-not-throw differently.  */
175850397Sobrien
175990075Sobrien  call_site_base = 1;
176090075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
176190075Sobrien    if (lp_info[i].directly_reachable)
176290075Sobrien      {
176390075Sobrien	int action = lp_info[i].action_index;
176490075Sobrien
176590075Sobrien	/* Map must-not-throw to otherwise unused call-site index 0.  */
176690075Sobrien	if (action == -2)
176790075Sobrien	  index = 0;
176890075Sobrien	/* Map no-action to otherwise unused call-site index -1.  */
176990075Sobrien	else if (action == -1)
177090075Sobrien	  index = -1;
177190075Sobrien	/* Otherwise, look it up in the table.  */
177290075Sobrien	else
177390075Sobrien	  index = add_call_site (GEN_INT (lp_info[i].dispatch_index), action);
177490075Sobrien
177590075Sobrien	lp_info[i].call_site_index = index;
177690075Sobrien      }
177790075Sobrien}
177890075Sobrien
177990075Sobrienstatic void
1780132718Skansjlj_mark_call_sites (struct sjlj_lp_info *lp_info)
178190075Sobrien{
178290075Sobrien  int last_call_site = -2;
178390075Sobrien  rtx insn, mem;
178490075Sobrien
178590075Sobrien  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
178650397Sobrien    {
178790075Sobrien      struct eh_region *region;
178890075Sobrien      int this_call_site;
178990075Sobrien      rtx note, before, p;
179050397Sobrien
179190075Sobrien      /* Reset value tracking at extended basic block boundaries.  */
1792169689Skan      if (LABEL_P (insn))
179390075Sobrien	last_call_site = -2;
179450397Sobrien
179590075Sobrien      if (! INSN_P (insn))
179690075Sobrien	continue;
179750397Sobrien
179890075Sobrien      note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
179990075Sobrien      if (!note)
180090075Sobrien	{
180190075Sobrien	  /* Calls (and trapping insns) without notes are outside any
180290075Sobrien	     exception handling region in this function.  Mark them as
180390075Sobrien	     no action.  */
1804169689Skan	  if (CALL_P (insn)
180590075Sobrien	      || (flag_non_call_exceptions
180690075Sobrien		  && may_trap_p (PATTERN (insn))))
180790075Sobrien	    this_call_site = -1;
180890075Sobrien	  else
180990075Sobrien	    continue;
181090075Sobrien	}
181190075Sobrien      else
181290075Sobrien	{
181390075Sobrien	  /* Calls that are known to not throw need not be marked.  */
181490075Sobrien	  if (INTVAL (XEXP (note, 0)) <= 0)
181590075Sobrien	    continue;
181650397Sobrien
1817169689Skan	  region = VEC_index (eh_region, cfun->eh->region_array, INTVAL (XEXP (note, 0)));
181890075Sobrien	  this_call_site = lp_info[region->region_number].call_site_index;
181990075Sobrien	}
182050397Sobrien
182190075Sobrien      if (this_call_site == last_call_site)
182290075Sobrien	continue;
182350397Sobrien
182490075Sobrien      /* Don't separate a call from it's argument loads.  */
182590075Sobrien      before = insn;
1826169689Skan      if (CALL_P (insn))
1827117395Skan	before = find_first_parameter_load (insn, NULL_RTX);
182850397Sobrien
182990075Sobrien      start_sequence ();
183090075Sobrien      mem = adjust_address (cfun->eh->sjlj_fc, TYPE_MODE (integer_type_node),
183190075Sobrien			    sjlj_fc_call_site_ofs);
183290075Sobrien      emit_move_insn (mem, GEN_INT (this_call_site));
183390075Sobrien      p = get_insns ();
183490075Sobrien      end_sequence ();
183550397Sobrien
1836117395Skan      emit_insn_before (p, before);
183790075Sobrien      last_call_site = this_call_site;
183850397Sobrien    }
183950397Sobrien}
184050397Sobrien
184190075Sobrien/* Construct the SjLj_Function_Context.  */
184250397Sobrien
184390075Sobrienstatic void
1844132718Skansjlj_emit_function_enter (rtx dispatch_label)
184550397Sobrien{
184690075Sobrien  rtx fn_begin, fc, mem, seq;
1847169689Skan  bool fn_begin_outside_block;
184850397Sobrien
184990075Sobrien  fc = cfun->eh->sjlj_fc;
185050397Sobrien
185190075Sobrien  start_sequence ();
185250397Sobrien
185390075Sobrien  /* We're storing this libcall's address into memory instead of
185490075Sobrien     calling it directly.  Thus, we must call assemble_external_libcall
185590075Sobrien     here, as we can not depend on emit_library_call to do it for us.  */
185690075Sobrien  assemble_external_libcall (eh_personality_libfunc);
185790075Sobrien  mem = adjust_address (fc, Pmode, sjlj_fc_personality_ofs);
185890075Sobrien  emit_move_insn (mem, eh_personality_libfunc);
185990075Sobrien
186090075Sobrien  mem = adjust_address (fc, Pmode, sjlj_fc_lsda_ofs);
186190075Sobrien  if (cfun->uses_eh_lsda)
186250397Sobrien    {
186390075Sobrien      char buf[20];
1864132718Skan      rtx sym;
1865132718Skan
1866117395Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LLSDA", current_function_funcdef_no);
1867132718Skan      sym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
1868132718Skan      SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_LOCAL;
1869132718Skan      emit_move_insn (mem, sym);
187050397Sobrien    }
187190075Sobrien  else
187290075Sobrien    emit_move_insn (mem, const0_rtx);
187350397Sobrien
187490075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP
187590075Sobrien  {
187690075Sobrien    rtx x, note;
187790075Sobrien    x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_RETURNS_TWICE,
187890075Sobrien				 TYPE_MODE (integer_type_node), 1,
187990075Sobrien				 plus_constant (XEXP (fc, 0),
188090075Sobrien						sjlj_fc_jbuf_ofs), Pmode);
188150397Sobrien
1882132718Skan    note = emit_note (NOTE_INSN_EXPECTED_VALUE);
188390075Sobrien    NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, x, const0_rtx);
188450397Sobrien
188590075Sobrien    emit_cmp_and_jump_insns (x, const0_rtx, NE, 0,
188690075Sobrien			     TYPE_MODE (integer_type_node), 0, dispatch_label);
188790075Sobrien  }
188890075Sobrien#else
188990075Sobrien  expand_builtin_setjmp_setup (plus_constant (XEXP (fc, 0), sjlj_fc_jbuf_ofs),
189090075Sobrien			       dispatch_label);
189190075Sobrien#endif
189250397Sobrien
189390075Sobrien  emit_library_call (unwind_sjlj_register_libfunc, LCT_NORMAL, VOIDmode,
189490075Sobrien		     1, XEXP (fc, 0), Pmode);
189590075Sobrien
189690075Sobrien  seq = get_insns ();
189750397Sobrien  end_sequence ();
189850397Sobrien
189990075Sobrien  /* ??? Instead of doing this at the beginning of the function,
190090075Sobrien     do this in a block that is at loop level 0 and dominates all
190190075Sobrien     can_throw_internal instructions.  */
190250397Sobrien
1903169689Skan  fn_begin_outside_block = true;
190490075Sobrien  for (fn_begin = get_insns (); ; fn_begin = NEXT_INSN (fn_begin))
1905169689Skan    if (NOTE_P (fn_begin))
1906169689Skan      {
1907169689Skan	if (NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG)
1908169689Skan	  break;
1909169689Skan	else if (NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_BASIC_BLOCK)
1910169689Skan	  fn_begin_outside_block = false;
1911169689Skan      }
1912169689Skan
1913169689Skan  if (fn_begin_outside_block)
1914169689Skan    insert_insn_on_edge (seq, single_succ_edge (ENTRY_BLOCK_PTR));
1915169689Skan  else
1916169689Skan    emit_insn_after (seq, fn_begin);
191750397Sobrien}
191850397Sobrien
191990075Sobrien/* Call back from expand_function_end to know where we should put
192090075Sobrien   the call to unwind_sjlj_unregister_libfunc if needed.  */
192150397Sobrien
192250397Sobrienvoid
1923132718Skansjlj_emit_function_exit_after (rtx after)
192450397Sobrien{
192590075Sobrien  cfun->eh->sjlj_exit_after = after;
192650397Sobrien}
192750397Sobrien
192890075Sobrienstatic void
1929132718Skansjlj_emit_function_exit (void)
193050397Sobrien{
193190075Sobrien  rtx seq;
1932169689Skan  edge e;
1933169689Skan  edge_iterator ei;
193450397Sobrien
193590075Sobrien  start_sequence ();
193650397Sobrien
193790075Sobrien  emit_library_call (unwind_sjlj_unregister_libfunc, LCT_NORMAL, VOIDmode,
193890075Sobrien		     1, XEXP (cfun->eh->sjlj_fc, 0), Pmode);
193950397Sobrien
194090075Sobrien  seq = get_insns ();
194190075Sobrien  end_sequence ();
194250397Sobrien
194390075Sobrien  /* ??? Really this can be done in any block at loop level 0 that
194490075Sobrien     post-dominates all can_throw_internal instructions.  This is
194590075Sobrien     the last possible moment.  */
194650397Sobrien
1947169689Skan  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
1948169689Skan    if (e->flags & EDGE_FALLTHRU)
1949169689Skan      break;
1950169689Skan  if (e)
1951169689Skan    {
1952169689Skan      rtx insn;
1953169689Skan
1954169689Skan      /* Figure out whether the place we are supposed to insert libcall
1955169689Skan         is inside the last basic block or after it.  In the other case
1956169689Skan         we need to emit to edge.  */
1957169689Skan      gcc_assert (e->src->next_bb == EXIT_BLOCK_PTR);
1958169689Skan      for (insn = BB_HEAD (e->src); ; insn = NEXT_INSN (insn))
1959169689Skan	{
1960169689Skan	  if (insn == cfun->eh->sjlj_exit_after)
1961169689Skan	    {
1962169689Skan	      if (LABEL_P (insn))
1963169689Skan		insn = NEXT_INSN (insn);
1964169689Skan	      emit_insn_after (seq, insn);
1965169689Skan	      return;
1966169689Skan	    }
1967169689Skan	  if (insn == BB_END (e->src))
1968169689Skan	    break;
1969169689Skan	}
1970169689Skan      insert_insn_on_edge (seq, e);
1971169689Skan    }
197290075Sobrien}
197350397Sobrien
197490075Sobrienstatic void
1975132718Skansjlj_emit_dispatch_table (rtx dispatch_label, struct sjlj_lp_info *lp_info)
197690075Sobrien{
197790075Sobrien  int i, first_reachable;
197890075Sobrien  rtx mem, dispatch, seq, fc;
1979169689Skan  rtx before;
1980169689Skan  basic_block bb;
1981169689Skan  edge e;
198250397Sobrien
198390075Sobrien  fc = cfun->eh->sjlj_fc;
198450397Sobrien
198590075Sobrien  start_sequence ();
198650397Sobrien
198790075Sobrien  emit_label (dispatch_label);
198850397Sobrien
198990075Sobrien#ifndef DONT_USE_BUILTIN_SETJMP
199090075Sobrien  expand_builtin_setjmp_receiver (dispatch_label);
199190075Sobrien#endif
199250397Sobrien
199390075Sobrien  /* Load up dispatch index, exc_ptr and filter values from the
199490075Sobrien     function context.  */
199590075Sobrien  mem = adjust_address (fc, TYPE_MODE (integer_type_node),
199690075Sobrien			sjlj_fc_call_site_ofs);
199790075Sobrien  dispatch = copy_to_reg (mem);
199850397Sobrien
199990075Sobrien  mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs);
2000132718Skan  if (word_mode != ptr_mode)
200150397Sobrien    {
200290075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED
2003132718Skan      mem = convert_memory_address (ptr_mode, mem);
200490075Sobrien#else
2005132718Skan      mem = convert_to_mode (ptr_mode, mem, 0);
200690075Sobrien#endif
200790075Sobrien    }
200890075Sobrien  emit_move_insn (cfun->eh->exc_ptr, mem);
200950397Sobrien
201090075Sobrien  mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs + UNITS_PER_WORD);
201190075Sobrien  emit_move_insn (cfun->eh->filter, mem);
201250397Sobrien
201390075Sobrien  /* Jump to one of the directly reachable regions.  */
201490075Sobrien  /* ??? This really ought to be using a switch statement.  */
201590075Sobrien
201690075Sobrien  first_reachable = 0;
201790075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
201890075Sobrien    {
201990075Sobrien      if (! lp_info[i].directly_reachable)
202090075Sobrien	continue;
202190075Sobrien
202290075Sobrien      if (! first_reachable)
202350397Sobrien	{
202490075Sobrien	  first_reachable = i;
202590075Sobrien	  continue;
202650397Sobrien	}
202790075Sobrien
202890075Sobrien      emit_cmp_and_jump_insns (dispatch, GEN_INT (lp_info[i].dispatch_index),
202990075Sobrien			       EQ, NULL_RTX, TYPE_MODE (integer_type_node), 0,
2030169689Skan	                       ((struct eh_region *)VEC_index (eh_region, cfun->eh->region_array, i))
2031169689Skan				->post_landing_pad);
203250397Sobrien    }
203350397Sobrien
203490075Sobrien  seq = get_insns ();
203590075Sobrien  end_sequence ();
203650397Sobrien
2037169689Skan  before = (((struct eh_region *)VEC_index (eh_region, cfun->eh->region_array, first_reachable))
2038169689Skan	    ->post_landing_pad);
2039169689Skan
2040169689Skan  bb = emit_to_new_bb_before (seq, before);
2041169689Skan  e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
2042169689Skan  e->count = bb->count;
2043169689Skan  e->probability = REG_BR_PROB_BASE;
204450397Sobrien}
204550397Sobrien
204650397Sobrienstatic void
2047132718Skansjlj_build_landing_pads (void)
204850397Sobrien{
204990075Sobrien  struct sjlj_lp_info *lp_info;
205050397Sobrien
2051169689Skan  lp_info = XCNEWVEC (struct sjlj_lp_info, cfun->eh->last_region_number + 1);
205250397Sobrien
205390075Sobrien  if (sjlj_find_directly_reachable_regions (lp_info))
205450397Sobrien    {
205590075Sobrien      rtx dispatch_label = gen_label_rtx ();
205652284Sobrien
205790075Sobrien      cfun->eh->sjlj_fc
205890075Sobrien	= assign_stack_local (TYPE_MODE (sjlj_fc_type_node),
205990075Sobrien			      int_size_in_bytes (sjlj_fc_type_node),
206090075Sobrien			      TYPE_ALIGN (sjlj_fc_type_node));
206150397Sobrien
206290075Sobrien      sjlj_assign_call_site_values (dispatch_label, lp_info);
206390075Sobrien      sjlj_mark_call_sites (lp_info);
206450397Sobrien
206590075Sobrien      sjlj_emit_function_enter (dispatch_label);
206690075Sobrien      sjlj_emit_dispatch_table (dispatch_label, lp_info);
206790075Sobrien      sjlj_emit_function_exit ();
206850397Sobrien    }
206950397Sobrien
207090075Sobrien  free (lp_info);
207150397Sobrien}
207250397Sobrien
207352284Sobrienvoid
2074132718Skanfinish_eh_generation (void)
207550397Sobrien{
2076169689Skan  basic_block bb;
2077169689Skan
207890075Sobrien  /* Nothing to do if no regions created.  */
207990075Sobrien  if (cfun->eh->region_tree == NULL)
208090075Sobrien    return;
208150397Sobrien
208290075Sobrien  /* The object here is to provide find_basic_blocks with detailed
208390075Sobrien     information (via reachable_handlers) on how exception control
208490075Sobrien     flows within the function.  In this first pass, we can include
208590075Sobrien     type information garnered from ERT_THROW and ERT_ALLOWED_EXCEPTIONS
208690075Sobrien     regions, and hope that it will be useful in deleting unreachable
208790075Sobrien     handlers.  Subsequently, we will generate landing pads which will
208890075Sobrien     connect many of the handlers, and then type information will not
208990075Sobrien     be effective.  Still, this is a win over previous implementations.  */
209050397Sobrien
209190075Sobrien  /* These registers are used by the landing pads.  Make sure they
209290075Sobrien     have been generated.  */
209390075Sobrien  get_exception_pointer (cfun);
209490075Sobrien  get_exception_filter (cfun);
209550397Sobrien
209690075Sobrien  /* Construct the landing pads.  */
209750397Sobrien
209890075Sobrien  assign_filter_values ();
209990075Sobrien  build_post_landing_pads ();
210090075Sobrien  connect_post_landing_pads ();
210190075Sobrien  if (USING_SJLJ_EXCEPTIONS)
210290075Sobrien    sjlj_build_landing_pads ();
210390075Sobrien  else
210490075Sobrien    dw2_build_landing_pads ();
210550397Sobrien
210690075Sobrien  cfun->eh->built_landing_pads = 1;
210750397Sobrien
210890075Sobrien  /* We've totally changed the CFG.  Start over.  */
210990075Sobrien  find_exception_handler_labels ();
2110169689Skan  break_superblocks ();
2111169689Skan  if (USING_SJLJ_EXCEPTIONS)
2112169689Skan    commit_edge_insertions ();
2113169689Skan  FOR_EACH_BB (bb)
2114169689Skan    {
2115169689Skan      edge e;
2116169689Skan      edge_iterator ei;
2117169689Skan      bool eh = false;
2118169689Skan      for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
2119169689Skan	{
2120169689Skan	  if (e->flags & EDGE_EH)
2121169689Skan	    {
2122169689Skan	      remove_edge (e);
2123169689Skan	      eh = true;
2124169689Skan	    }
2125169689Skan	  else
2126169689Skan	    ei_next (&ei);
2127169689Skan	}
2128169689Skan      if (eh)
2129169689Skan	rtl_make_eh_edge (NULL, bb, BB_END (bb));
2130169689Skan    }
213190075Sobrien}
213290075Sobrien
213396263Sobrienstatic hashval_t
2134132718Skanehl_hash (const void *pentry)
213596263Sobrien{
213696263Sobrien  struct ehl_map_entry *entry = (struct ehl_map_entry *) pentry;
213796263Sobrien
213896263Sobrien  /* 2^32 * ((sqrt(5) - 1) / 2) */
213996263Sobrien  const hashval_t scaled_golden_ratio = 0x9e3779b9;
214096263Sobrien  return CODE_LABEL_NUMBER (entry->label) * scaled_golden_ratio;
214196263Sobrien}
214296263Sobrien
214396263Sobrienstatic int
2144132718Skanehl_eq (const void *pentry, const void *pdata)
214596263Sobrien{
214696263Sobrien  struct ehl_map_entry *entry = (struct ehl_map_entry *) pentry;
214796263Sobrien  struct ehl_map_entry *data = (struct ehl_map_entry *) pdata;
214896263Sobrien
214996263Sobrien  return entry->label == data->label;
215096263Sobrien}
215196263Sobrien
215290075Sobrien/* This section handles removing dead code for flow.  */
215352284Sobrien
215496263Sobrien/* Remove LABEL from exception_handler_label_map.  */
215550397Sobrien
215690075Sobrienstatic void
2157132718Skanremove_exception_handler_label (rtx label)
215890075Sobrien{
215996263Sobrien  struct ehl_map_entry **slot, tmp;
216050397Sobrien
216196263Sobrien  /* If exception_handler_label_map was not built yet,
216290075Sobrien     there is nothing to do.  */
2163117395Skan  if (cfun->eh->exception_handler_label_map == NULL)
216490075Sobrien    return;
216550397Sobrien
216696263Sobrien  tmp.label = label;
216796263Sobrien  slot = (struct ehl_map_entry **)
2168117395Skan    htab_find_slot (cfun->eh->exception_handler_label_map, &tmp, NO_INSERT);
2169169689Skan  gcc_assert (slot);
217050397Sobrien
2171117395Skan  htab_clear_slot (cfun->eh->exception_handler_label_map, (void **) slot);
217250397Sobrien}
217350397Sobrien
217490075Sobrien/* Splice REGION from the region tree etc.  */
217550397Sobrien
217690075Sobrienstatic void
2177132718Skanremove_eh_handler (struct eh_region *region)
217850397Sobrien{
217996263Sobrien  struct eh_region **pp, **pp_start, *p, *outer, *inner;
218090075Sobrien  rtx lab;
218150397Sobrien
218290075Sobrien  /* For the benefit of efficiently handling REG_EH_REGION notes,
218390075Sobrien     replace this region in the region array with its containing
218490075Sobrien     region.  Note that previous region deletions may result in
218596263Sobrien     multiple copies of this region in the array, so we have a
218696263Sobrien     list of alternate numbers by which we are known.  */
218750397Sobrien
218896263Sobrien  outer = region->outer;
2189169689Skan  VEC_replace (eh_region, cfun->eh->region_array, region->region_number, outer);
219096263Sobrien  if (region->aka)
219196263Sobrien    {
2192169689Skan      unsigned i;
2193169689Skan      bitmap_iterator bi;
2194169689Skan
2195169689Skan      EXECUTE_IF_SET_IN_BITMAP (region->aka, 0, i, bi)
2196169689Skan	{
2197169689Skan          VEC_replace (eh_region, cfun->eh->region_array, i, outer);
2198169689Skan	}
219996263Sobrien    }
220096263Sobrien
220196263Sobrien  if (outer)
220296263Sobrien    {
220396263Sobrien      if (!outer->aka)
2204117395Skan        outer->aka = BITMAP_GGC_ALLOC ();
220596263Sobrien      if (region->aka)
2206169689Skan	bitmap_ior_into (outer->aka, region->aka);
220796263Sobrien      bitmap_set_bit (outer->aka, region->region_number);
220896263Sobrien    }
220996263Sobrien
221090075Sobrien  if (cfun->eh->built_landing_pads)
221190075Sobrien    lab = region->landing_pad;
221290075Sobrien  else
221390075Sobrien    lab = region->label;
221490075Sobrien  if (lab)
221590075Sobrien    remove_exception_handler_label (lab);
221650397Sobrien
221796263Sobrien  if (outer)
221896263Sobrien    pp_start = &outer->inner;
221990075Sobrien  else
222096263Sobrien    pp_start = &cfun->eh->region_tree;
222196263Sobrien  for (pp = pp_start, p = *pp; p != region; pp = &p->next_peer, p = *pp)
222290075Sobrien    continue;
222396263Sobrien  *pp = region->next_peer;
222450397Sobrien
222596263Sobrien  inner = region->inner;
222696263Sobrien  if (inner)
222790075Sobrien    {
222896263Sobrien      for (p = inner; p->next_peer ; p = p->next_peer)
222996263Sobrien	p->outer = outer;
223096263Sobrien      p->outer = outer;
223196263Sobrien
223296263Sobrien      p->next_peer = *pp_start;
223396263Sobrien      *pp_start = inner;
223490075Sobrien    }
223550397Sobrien
223690075Sobrien  if (region->type == ERT_CATCH)
223790075Sobrien    {
223890075Sobrien      struct eh_region *try, *next, *prev;
223952284Sobrien
224090075Sobrien      for (try = region->next_peer;
224190075Sobrien	   try->type == ERT_CATCH;
224290075Sobrien	   try = try->next_peer)
224390075Sobrien	continue;
2244169689Skan      gcc_assert (try->type == ERT_TRY);
224590075Sobrien
224690075Sobrien      next = region->u.catch.next_catch;
224790075Sobrien      prev = region->u.catch.prev_catch;
224890075Sobrien
224990075Sobrien      if (next)
225090075Sobrien	next->u.catch.prev_catch = prev;
225190075Sobrien      else
225290075Sobrien	try->u.try.last_catch = prev;
225390075Sobrien      if (prev)
225490075Sobrien	prev->u.catch.next_catch = next;
225590075Sobrien      else
225690075Sobrien	{
225790075Sobrien	  try->u.try.catch = next;
225890075Sobrien	  if (! next)
225990075Sobrien	    remove_eh_handler (try);
226090075Sobrien	}
226190075Sobrien    }
226250397Sobrien}
226350397Sobrien
226490075Sobrien/* LABEL heads a basic block that is about to be deleted.  If this
226590075Sobrien   label corresponds to an exception region, we may be able to
226690075Sobrien   delete the region.  */
226750397Sobrien
226850397Sobrienvoid
2269132718Skanmaybe_remove_eh_handler (rtx label)
227050397Sobrien{
227196263Sobrien  struct ehl_map_entry **slot, tmp;
227296263Sobrien  struct eh_region *region;
227350397Sobrien
227490075Sobrien  /* ??? After generating landing pads, it's not so simple to determine
227590075Sobrien     if the region data is completely unused.  One must examine the
227690075Sobrien     landing pad and the post landing pad, and whether an inner try block
227790075Sobrien     is referencing the catch handlers directly.  */
227890075Sobrien  if (cfun->eh->built_landing_pads)
227950397Sobrien    return;
228050397Sobrien
228196263Sobrien  tmp.label = label;
228296263Sobrien  slot = (struct ehl_map_entry **)
2283117395Skan    htab_find_slot (cfun->eh->exception_handler_label_map, &tmp, NO_INSERT);
228496263Sobrien  if (! slot)
228596263Sobrien    return;
228696263Sobrien  region = (*slot)->region;
228796263Sobrien  if (! region)
228896263Sobrien    return;
228996263Sobrien
229096263Sobrien  /* Flow will want to remove MUST_NOT_THROW regions as unreachable
229196263Sobrien     because there is no path to the fallback call to terminate.
229296263Sobrien     But the region continues to affect call-site data until there
229396263Sobrien     are no more contained calls, which we don't see here.  */
229496263Sobrien  if (region->type == ERT_MUST_NOT_THROW)
229550397Sobrien    {
2296117395Skan      htab_clear_slot (cfun->eh->exception_handler_label_map, (void **) slot);
229796263Sobrien      region->label = NULL_RTX;
229850397Sobrien    }
229996263Sobrien  else
230096263Sobrien    remove_eh_handler (region);
230150397Sobrien}
230250397Sobrien
230396263Sobrien/* Invokes CALLBACK for every exception handler label.  Only used by old
230496263Sobrien   loop hackery; should not be used by new code.  */
230596263Sobrien
230696263Sobrienvoid
2307132718Skanfor_each_eh_label (void (*callback) (rtx))
230896263Sobrien{
2309117395Skan  htab_traverse (cfun->eh->exception_handler_label_map, for_each_eh_label_1,
2310132718Skan		 (void *) &callback);
231196263Sobrien}
231296263Sobrien
231396263Sobrienstatic int
2314132718Skanfor_each_eh_label_1 (void **pentry, void *data)
231596263Sobrien{
231696263Sobrien  struct ehl_map_entry *entry = *(struct ehl_map_entry **)pentry;
2317132718Skan  void (*callback) (rtx) = *(void (**) (rtx)) data;
231896263Sobrien
231996263Sobrien  (*callback) (entry->label);
232096263Sobrien  return 1;
232196263Sobrien}
2322169689Skan
2323169689Skan/* Invoke CALLBACK for every exception region in the current function.  */
2324169689Skan
2325169689Skanvoid
2326169689Skanfor_each_eh_region (void (*callback) (struct eh_region *))
2327169689Skan{
2328169689Skan  int i, n = cfun->eh->last_region_number;
2329169689Skan  for (i = 1; i <= n; ++i)
2330169689Skan    {
2331169689Skan      struct eh_region *region;
2332169689Skan
2333169689Skan      region = VEC_index (eh_region, cfun->eh->region_array, i);
2334169689Skan      if (region)
2335169689Skan	(*callback) (region);
2336169689Skan    }
2337169689Skan}
233890075Sobrien
233990075Sobrien/* This section describes CFG exception edges for flow.  */
234050397Sobrien
234190075Sobrien/* For communicating between calls to reachable_next_level.  */
2342169689Skanstruct reachable_info
234350397Sobrien{
234490075Sobrien  tree types_caught;
234590075Sobrien  tree types_allowed;
2346169689Skan  void (*callback) (struct eh_region *, void *);
2347169689Skan  void *callback_data;
2348169689Skan  bool saw_any_handlers;
234990075Sobrien};
235090075Sobrien
235190075Sobrien/* A subroutine of reachable_next_level.  Return true if TYPE, or a
235290075Sobrien   base class of TYPE, is in HANDLED.  */
235390075Sobrien
235490075Sobrienstatic int
2355132718Skancheck_handled (tree handled, tree type)
235690075Sobrien{
235790075Sobrien  tree t;
235890075Sobrien
235990075Sobrien  /* We can check for exact matches without front-end help.  */
236090075Sobrien  if (! lang_eh_type_covers)
236190075Sobrien    {
236290075Sobrien      for (t = handled; t ; t = TREE_CHAIN (t))
236390075Sobrien	if (TREE_VALUE (t) == type)
236490075Sobrien	  return 1;
236590075Sobrien    }
236690075Sobrien  else
236790075Sobrien    {
236890075Sobrien      for (t = handled; t ; t = TREE_CHAIN (t))
236990075Sobrien	if ((*lang_eh_type_covers) (TREE_VALUE (t), type))
237090075Sobrien	  return 1;
237190075Sobrien    }
237290075Sobrien
237350397Sobrien  return 0;
237450397Sobrien}
237550397Sobrien
237690075Sobrien/* A subroutine of reachable_next_level.  If we are collecting a list
237790075Sobrien   of handlers, add one.  After landing pad generation, reference
237890075Sobrien   it instead of the handlers themselves.  Further, the handlers are
237990075Sobrien   all wired together, so by referencing one, we've got them all.
238090075Sobrien   Before landing pad generation we reference each handler individually.
238150397Sobrien
238290075Sobrien   LP_REGION contains the landing pad; REGION is the handler.  */
238350397Sobrien
238490075Sobrienstatic void
2385169689Skanadd_reachable_handler (struct reachable_info *info,
2386169689Skan		       struct eh_region *lp_region, struct eh_region *region)
238750397Sobrien{
238890075Sobrien  if (! info)
238950397Sobrien    return;
239050397Sobrien
2391169689Skan  info->saw_any_handlers = true;
2392169689Skan
239390075Sobrien  if (cfun->eh->built_landing_pads)
2394169689Skan    info->callback (lp_region, info->callback_data);
239590075Sobrien  else
2396169689Skan    info->callback (region, info->callback_data);
239750397Sobrien}
239850397Sobrien
239990075Sobrien/* Process one level of exception regions for reachability.
240090075Sobrien   If TYPE_THROWN is non-null, then it is the *exact* type being
240190075Sobrien   propagated.  If INFO is non-null, then collect handler labels
240290075Sobrien   and caught/allowed type information between invocations.  */
240350397Sobrien
240490075Sobrienstatic enum reachable_code
2405132718Skanreachable_next_level (struct eh_region *region, tree type_thrown,
2406132718Skan		      struct reachable_info *info)
240750397Sobrien{
240890075Sobrien  switch (region->type)
240990075Sobrien    {
241090075Sobrien    case ERT_CLEANUP:
241190075Sobrien      /* Before landing-pad generation, we model control flow
241290075Sobrien	 directly to the individual handlers.  In this way we can
241390075Sobrien	 see that catch handler types may shadow one another.  */
241490075Sobrien      add_reachable_handler (info, region, region);
241590075Sobrien      return RNL_MAYBE_CAUGHT;
241650397Sobrien
241790075Sobrien    case ERT_TRY:
241890075Sobrien      {
241990075Sobrien	struct eh_region *c;
242090075Sobrien	enum reachable_code ret = RNL_NOT_CAUGHT;
242150397Sobrien
242290075Sobrien	for (c = region->u.try.catch; c ; c = c->u.catch.next_catch)
242390075Sobrien	  {
242490075Sobrien	    /* A catch-all handler ends the search.  */
242590075Sobrien	    if (c->u.catch.type_list == NULL)
242690075Sobrien	      {
242790075Sobrien		add_reachable_handler (info, region, c);
242890075Sobrien		return RNL_CAUGHT;
242990075Sobrien	      }
243050397Sobrien
243190075Sobrien	    if (type_thrown)
243290075Sobrien	      {
243390075Sobrien		/* If we have at least one type match, end the search.  */
243490075Sobrien		tree tp_node = c->u.catch.type_list;
243550397Sobrien
243690075Sobrien		for (; tp_node; tp_node = TREE_CHAIN (tp_node))
243790075Sobrien		  {
243890075Sobrien		    tree type = TREE_VALUE (tp_node);
243950397Sobrien
244090075Sobrien		    if (type == type_thrown
244190075Sobrien			|| (lang_eh_type_covers
244290075Sobrien			    && (*lang_eh_type_covers) (type, type_thrown)))
244390075Sobrien		      {
244490075Sobrien			add_reachable_handler (info, region, c);
244590075Sobrien			return RNL_CAUGHT;
244690075Sobrien		      }
244790075Sobrien		  }
244850397Sobrien
244990075Sobrien		/* If we have definitive information of a match failure,
245090075Sobrien		   the catch won't trigger.  */
245190075Sobrien		if (lang_eh_type_covers)
245290075Sobrien		  return RNL_NOT_CAUGHT;
245390075Sobrien	      }
245450397Sobrien
245590075Sobrien	    /* At this point, we either don't know what type is thrown or
245690075Sobrien	       don't have front-end assistance to help deciding if it is
245790075Sobrien	       covered by one of the types in the list for this region.
245850397Sobrien
245990075Sobrien	       We'd then like to add this region to the list of reachable
246090075Sobrien	       handlers since it is indeed potentially reachable based on the
246190075Sobrien	       information we have.
246250397Sobrien
246390075Sobrien	       Actually, this handler is for sure not reachable if all the
246490075Sobrien	       types it matches have already been caught. That is, it is only
246590075Sobrien	       potentially reachable if at least one of the types it catches
246690075Sobrien	       has not been previously caught.  */
246750397Sobrien
246890075Sobrien	    if (! info)
246990075Sobrien	      ret = RNL_MAYBE_CAUGHT;
247090075Sobrien	    else
247190075Sobrien	      {
247290075Sobrien		tree tp_node = c->u.catch.type_list;
247390075Sobrien		bool maybe_reachable = false;
247450397Sobrien
247590075Sobrien		/* Compute the potential reachability of this handler and
247690075Sobrien		   update the list of types caught at the same time.  */
247790075Sobrien		for (; tp_node; tp_node = TREE_CHAIN (tp_node))
247890075Sobrien		  {
247990075Sobrien		    tree type = TREE_VALUE (tp_node);
248090075Sobrien
248190075Sobrien		    if (! check_handled (info->types_caught, type))
248290075Sobrien		      {
248390075Sobrien			info->types_caught
248490075Sobrien			  = tree_cons (NULL, type, info->types_caught);
248590075Sobrien
248690075Sobrien			maybe_reachable = true;
248790075Sobrien		      }
248890075Sobrien		  }
248990075Sobrien
249090075Sobrien		if (maybe_reachable)
249190075Sobrien		  {
249290075Sobrien		    add_reachable_handler (info, region, c);
249390075Sobrien
249490075Sobrien		    /* ??? If the catch type is a base class of every allowed
249590075Sobrien		       type, then we know we can stop the search.  */
249690075Sobrien		    ret = RNL_MAYBE_CAUGHT;
249790075Sobrien		  }
249890075Sobrien	      }
249990075Sobrien	  }
250090075Sobrien
250190075Sobrien	return ret;
250290075Sobrien      }
250390075Sobrien
250490075Sobrien    case ERT_ALLOWED_EXCEPTIONS:
250590075Sobrien      /* An empty list of types definitely ends the search.  */
250690075Sobrien      if (region->u.allowed.type_list == NULL_TREE)
250790075Sobrien	{
250890075Sobrien	  add_reachable_handler (info, region, region);
250990075Sobrien	  return RNL_CAUGHT;
251090075Sobrien	}
251190075Sobrien
251290075Sobrien      /* Collect a list of lists of allowed types for use in detecting
251390075Sobrien	 when a catch may be transformed into a catch-all.  */
251490075Sobrien      if (info)
251590075Sobrien	info->types_allowed = tree_cons (NULL_TREE,
251690075Sobrien					 region->u.allowed.type_list,
251790075Sobrien					 info->types_allowed);
251890075Sobrien
251990075Sobrien      /* If we have definitive information about the type hierarchy,
252090075Sobrien	 then we can tell if the thrown type will pass through the
252190075Sobrien	 filter.  */
252290075Sobrien      if (type_thrown && lang_eh_type_covers)
252390075Sobrien	{
252490075Sobrien	  if (check_handled (region->u.allowed.type_list, type_thrown))
252590075Sobrien	    return RNL_NOT_CAUGHT;
252690075Sobrien	  else
252790075Sobrien	    {
252890075Sobrien	      add_reachable_handler (info, region, region);
252990075Sobrien	      return RNL_CAUGHT;
253090075Sobrien	    }
253190075Sobrien	}
253290075Sobrien
253390075Sobrien      add_reachable_handler (info, region, region);
253490075Sobrien      return RNL_MAYBE_CAUGHT;
253590075Sobrien
253690075Sobrien    case ERT_CATCH:
2537132718Skan      /* Catch regions are handled by their controlling try region.  */
253890075Sobrien      return RNL_NOT_CAUGHT;
253990075Sobrien
254090075Sobrien    case ERT_MUST_NOT_THROW:
254190075Sobrien      /* Here we end our search, since no exceptions may propagate.
254290075Sobrien	 If we've touched down at some landing pad previous, then the
254390075Sobrien	 explicit function call we generated may be used.  Otherwise
2544169689Skan	 the call is made by the runtime.
2545169689Skan
2546169689Skan         Before inlining, do not perform this optimization.  We may
2547169689Skan	 inline a subroutine that contains handlers, and that will
2548169689Skan	 change the value of saw_any_handlers.  */
2549169689Skan
2550169689Skan      if ((info && info->saw_any_handlers) || !cfun->after_inlining)
255190075Sobrien	{
255290075Sobrien	  add_reachable_handler (info, region, region);
2553117395Skan	  return RNL_CAUGHT;
255490075Sobrien	}
255590075Sobrien      else
255690075Sobrien	return RNL_BLOCKED;
255790075Sobrien
255890075Sobrien    case ERT_THROW:
255990075Sobrien    case ERT_UNKNOWN:
256090075Sobrien      /* Shouldn't see these here.  */
2561169689Skan      gcc_unreachable ();
256290075Sobrien      break;
2563169689Skan    default:
2564169689Skan      gcc_unreachable ();
256590075Sobrien    }
256650397Sobrien}
256750397Sobrien
2568169689Skan/* Invoke CALLBACK on each region reachable from REGION_NUMBER.  */
256950397Sobrien
2570169689Skanvoid
2571169689Skanforeach_reachable_handler (int region_number, bool is_resx,
2572169689Skan			   void (*callback) (struct eh_region *, void *),
2573169689Skan			   void *callback_data)
257450397Sobrien{
257590075Sobrien  struct reachable_info info;
257690075Sobrien  struct eh_region *region;
257790075Sobrien  tree type_thrown;
257850397Sobrien
257990075Sobrien  memset (&info, 0, sizeof (info));
2580169689Skan  info.callback = callback;
2581169689Skan  info.callback_data = callback_data;
258250397Sobrien
2583169689Skan  region = VEC_index (eh_region, cfun->eh->region_array, region_number);
258450397Sobrien
258590075Sobrien  type_thrown = NULL_TREE;
2586169689Skan  if (is_resx)
258790075Sobrien    {
258890075Sobrien      /* A RESX leaves a region instead of entering it.  Thus the
258990075Sobrien	 region itself may have been deleted out from under us.  */
259090075Sobrien      if (region == NULL)
2591169689Skan	return;
259290075Sobrien      region = region->outer;
259390075Sobrien    }
259490075Sobrien  else if (region->type == ERT_THROW)
259590075Sobrien    {
259690075Sobrien      type_thrown = region->u.throw.type;
259790075Sobrien      region = region->outer;
259890075Sobrien    }
259950397Sobrien
2600117395Skan  while (region)
2601117395Skan    {
2602117395Skan      if (reachable_next_level (region, type_thrown, &info) >= RNL_CAUGHT)
2603117395Skan	break;
2604117395Skan      /* If we have processed one cleanup, there is no point in
2605117395Skan	 processing any more of them.  Each cleanup will have an edge
2606117395Skan	 to the next outer cleanup region, so the flow graph will be
2607117395Skan	 accurate.  */
2608117395Skan      if (region->type == ERT_CLEANUP)
2609117395Skan	region = region->u.cleanup.prev_try;
2610117395Skan      else
2611117395Skan	region = region->outer;
2612117395Skan    }
2613169689Skan}
2614132718Skan
2615169689Skan/* Retrieve a list of labels of exception handlers which can be
2616169689Skan   reached by a given insn.  */
2617169689Skan
2618169689Skanstatic void
2619169689Skanarh_to_landing_pad (struct eh_region *region, void *data)
2620169689Skan{
2621169689Skan  rtx *p_handlers = data;
2622169689Skan  if (! *p_handlers)
2623169689Skan    *p_handlers = alloc_INSN_LIST (region->landing_pad, NULL_RTX);
262490075Sobrien}
262550397Sobrien
2626169689Skanstatic void
2627169689Skanarh_to_label (struct eh_region *region, void *data)
2628169689Skan{
2629169689Skan  rtx *p_handlers = data;
2630169689Skan  *p_handlers = alloc_INSN_LIST (region->label, *p_handlers);
2631169689Skan}
2632169689Skan
2633169689Skanrtx
2634169689Skanreachable_handlers (rtx insn)
2635169689Skan{
2636169689Skan  bool is_resx = false;
2637169689Skan  rtx handlers = NULL;
2638169689Skan  int region_number;
2639169689Skan
2640169689Skan  if (JUMP_P (insn)
2641169689Skan      && GET_CODE (PATTERN (insn)) == RESX)
2642169689Skan    {
2643169689Skan      region_number = XINT (PATTERN (insn), 0);
2644169689Skan      is_resx = true;
2645169689Skan    }
2646169689Skan  else
2647169689Skan    {
2648169689Skan      rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
2649169689Skan      if (!note || INTVAL (XEXP (note, 0)) <= 0)
2650169689Skan	return NULL;
2651169689Skan      region_number = INTVAL (XEXP (note, 0));
2652169689Skan    }
2653169689Skan
2654169689Skan  foreach_reachable_handler (region_number, is_resx,
2655169689Skan			     (cfun->eh->built_landing_pads
2656169689Skan			      ? arh_to_landing_pad
2657169689Skan			      : arh_to_label),
2658169689Skan			     &handlers);
2659169689Skan
2660169689Skan  return handlers;
2661169689Skan}
2662169689Skan
266390075Sobrien/* Determine if the given INSN can throw an exception that is caught
266490075Sobrien   within the function.  */
266590075Sobrien
266690075Sobrienbool
2667169689Skancan_throw_internal_1 (int region_number, bool is_resx)
266850397Sobrien{
266990075Sobrien  struct eh_region *region;
267090075Sobrien  tree type_thrown;
267150397Sobrien
2672169689Skan  region = VEC_index (eh_region, cfun->eh->region_array, region_number);
267350397Sobrien
267490075Sobrien  type_thrown = NULL_TREE;
2675169689Skan  if (is_resx)
2676169689Skan    region = region->outer;
2677169689Skan  else if (region->type == ERT_THROW)
267890075Sobrien    {
267990075Sobrien      type_thrown = region->u.throw.type;
268090075Sobrien      region = region->outer;
268150397Sobrien    }
268250397Sobrien
268390075Sobrien  /* If this exception is ignored by each and every containing region,
268490075Sobrien     then control passes straight out.  The runtime may handle some
268590075Sobrien     regions, which also do not require processing internally.  */
268690075Sobrien  for (; region; region = region->outer)
268750397Sobrien    {
268890075Sobrien      enum reachable_code how = reachable_next_level (region, type_thrown, 0);
268990075Sobrien      if (how == RNL_BLOCKED)
269090075Sobrien	return false;
269190075Sobrien      if (how != RNL_NOT_CAUGHT)
2692117395Skan	return true;
269390075Sobrien    }
269450397Sobrien
269590075Sobrien  return false;
269690075Sobrien}
269750397Sobrien
2698169689Skanbool
2699169689Skancan_throw_internal (rtx insn)
2700169689Skan{
2701169689Skan  rtx note;
2702169689Skan
2703169689Skan  if (! INSN_P (insn))
2704169689Skan    return false;
2705169689Skan
2706169689Skan  if (JUMP_P (insn)
2707169689Skan      && GET_CODE (PATTERN (insn)) == RESX
2708169689Skan      && XINT (PATTERN (insn), 0) > 0)
2709169689Skan    return can_throw_internal_1 (XINT (PATTERN (insn), 0), true);
2710169689Skan
2711169689Skan  if (NONJUMP_INSN_P (insn)
2712169689Skan      && GET_CODE (PATTERN (insn)) == SEQUENCE)
2713169689Skan    insn = XVECEXP (PATTERN (insn), 0, 0);
2714169689Skan
2715169689Skan  /* Every insn that might throw has an EH_REGION note.  */
2716169689Skan  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
2717169689Skan  if (!note || INTVAL (XEXP (note, 0)) <= 0)
2718169689Skan    return false;
2719169689Skan
2720169689Skan  return can_throw_internal_1 (INTVAL (XEXP (note, 0)), false);
2721169689Skan}
2722169689Skan
272390075Sobrien/* Determine if the given INSN can throw an exception that is
272490075Sobrien   visible outside the function.  */
272550397Sobrien
272690075Sobrienbool
2727169689Skancan_throw_external_1 (int region_number, bool is_resx)
272890075Sobrien{
272990075Sobrien  struct eh_region *region;
273090075Sobrien  tree type_thrown;
2731169689Skan
2732169689Skan  region = VEC_index (eh_region, cfun->eh->region_array, region_number);
2733169689Skan
2734169689Skan  type_thrown = NULL_TREE;
2735169689Skan  if (is_resx)
2736169689Skan    region = region->outer;
2737169689Skan  else if (region->type == ERT_THROW)
2738169689Skan    {
2739169689Skan      type_thrown = region->u.throw.type;
2740169689Skan      region = region->outer;
2741169689Skan    }
2742169689Skan
2743169689Skan  /* If the exception is caught or blocked by any containing region,
2744169689Skan     then it is not seen by any calling function.  */
2745169689Skan  for (; region ; region = region->outer)
2746169689Skan    if (reachable_next_level (region, type_thrown, NULL) >= RNL_CAUGHT)
2747169689Skan      return false;
2748169689Skan
2749169689Skan  return true;
2750169689Skan}
2751169689Skan
2752169689Skanbool
2753169689Skancan_throw_external (rtx insn)
2754169689Skan{
275590075Sobrien  rtx note;
275650397Sobrien
275790075Sobrien  if (! INSN_P (insn))
275890075Sobrien    return false;
275990075Sobrien
2760169689Skan  if (JUMP_P (insn)
2761169689Skan      && GET_CODE (PATTERN (insn)) == RESX
2762169689Skan      && XINT (PATTERN (insn), 0) > 0)
2763169689Skan    return can_throw_external_1 (XINT (PATTERN (insn), 0), true);
2764169689Skan
2765169689Skan  if (NONJUMP_INSN_P (insn)
276690075Sobrien      && GET_CODE (PATTERN (insn)) == SEQUENCE)
276790075Sobrien    insn = XVECEXP (PATTERN (insn), 0, 0);
276890075Sobrien
276990075Sobrien  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
277090075Sobrien  if (!note)
277190075Sobrien    {
277290075Sobrien      /* Calls (and trapping insns) without notes are outside any
277390075Sobrien	 exception handling region in this function.  We have to
277490075Sobrien	 assume it might throw.  Given that the front end and middle
277590075Sobrien	 ends mark known NOTHROW functions, this isn't so wildly
277690075Sobrien	 inaccurate.  */
2777169689Skan      return (CALL_P (insn)
277890075Sobrien	      || (flag_non_call_exceptions
277990075Sobrien		  && may_trap_p (PATTERN (insn))));
278090075Sobrien    }
278190075Sobrien  if (INTVAL (XEXP (note, 0)) <= 0)
278290075Sobrien    return false;
278390075Sobrien
2784169689Skan  return can_throw_external_1 (INTVAL (XEXP (note, 0)), false);
278550397Sobrien}
278650397Sobrien
2787169689Skan/* Set TREE_NOTHROW and cfun->all_throwers_are_sibcalls.  */
278850397Sobrien
2789169689Skanunsigned int
2790132718Skanset_nothrow_function_flags (void)
279150397Sobrien{
279250397Sobrien  rtx insn;
2793132718Skan
2794169689Skan  /* If we don't know that this implementation of the function will
2795169689Skan     actually be used, then we must not set TREE_NOTHROW, since
2796169689Skan     callers must not assume that this function does not throw.  */
2797169689Skan  if (DECL_REPLACEABLE_P (current_function_decl))
2798169689Skan    return 0;
279950397Sobrien
2800169689Skan  TREE_NOTHROW (current_function_decl) = 1;
2801169689Skan
2802117395Skan  /* Assume cfun->all_throwers_are_sibcalls until we encounter
2803117395Skan     something that can throw an exception.  We specifically exempt
2804117395Skan     CALL_INSNs that are SIBLING_CALL_P, as these are really jumps,
2805117395Skan     and can't throw.  Most CALL_INSNs are not SIBLING_CALL_P, so this
2806117395Skan     is optimistic.  */
2807117395Skan
2808117395Skan  cfun->all_throwers_are_sibcalls = 1;
2809117395Skan
281090075Sobrien  if (! flag_exceptions)
2811169689Skan    return 0;
2812132718Skan
281350397Sobrien  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
281490075Sobrien    if (can_throw_external (insn))
2815117395Skan      {
2816169689Skan        TREE_NOTHROW (current_function_decl) = 0;
2817117395Skan
2818169689Skan	if (!CALL_P (insn) || !SIBLING_CALL_P (insn))
2819117395Skan	  {
2820117395Skan	    cfun->all_throwers_are_sibcalls = 0;
2821169689Skan	    return 0;
2822117395Skan	  }
2823117395Skan      }
2824117395Skan
282590075Sobrien  for (insn = current_function_epilogue_delay_list; insn;
282690075Sobrien       insn = XEXP (insn, 1))
282790075Sobrien    if (can_throw_external (insn))
2828117395Skan      {
2829169689Skan        TREE_NOTHROW (current_function_decl) = 0;
283090075Sobrien
2831169689Skan	if (!CALL_P (insn) || !SIBLING_CALL_P (insn))
2832117395Skan	  {
2833117395Skan	    cfun->all_throwers_are_sibcalls = 0;
2834169689Skan	    return 0;
2835117395Skan	  }
2836117395Skan      }
2837169689Skan  return 0;
283850397Sobrien}
283990075Sobrien
2840169689Skanstruct tree_opt_pass pass_set_nothrow_function_flags =
2841169689Skan{
2842169689Skan  NULL,                                 /* name */
2843169689Skan  NULL,                                 /* gate */
2844169689Skan  set_nothrow_function_flags,           /* execute */
2845169689Skan  NULL,                                 /* sub */
2846169689Skan  NULL,                                 /* next */
2847169689Skan  0,                                    /* static_pass_number */
2848169689Skan  0,                                    /* tv_id */
2849169689Skan  0,                                    /* properties_required */
2850169689Skan  0,                                    /* properties_provided */
2851169689Skan  0,                                    /* properties_destroyed */
2852169689Skan  0,                                    /* todo_flags_start */
2853169689Skan  0,                                    /* todo_flags_finish */
2854169689Skan  0                                     /* letter */
2855169689Skan};
2856169689Skan
285750397Sobrien
285890075Sobrien/* Various hooks for unwind library.  */
285950397Sobrien
286050397Sobrien/* Do any necessary initialization to access arbitrary stack frames.
286150397Sobrien   On the SPARC, this means flushing the register windows.  */
286250397Sobrien
286350397Sobrienvoid
2864132718Skanexpand_builtin_unwind_init (void)
286550397Sobrien{
286650397Sobrien  /* Set this so all the registers get saved in our frame; we need to be
286790075Sobrien     able to copy the saved values for any registers from frames we unwind.  */
286850397Sobrien  current_function_has_nonlocal_label = 1;
286950397Sobrien
287050397Sobrien#ifdef SETUP_FRAME_ADDRESSES
287150397Sobrien  SETUP_FRAME_ADDRESSES ();
287250397Sobrien#endif
287350397Sobrien}
287450397Sobrien
287590075Sobrienrtx
2876132718Skanexpand_builtin_eh_return_data_regno (tree arglist)
287790075Sobrien{
287890075Sobrien  tree which = TREE_VALUE (arglist);
287990075Sobrien  unsigned HOST_WIDE_INT iwhich;
288090075Sobrien
288190075Sobrien  if (TREE_CODE (which) != INTEGER_CST)
288290075Sobrien    {
2883169689Skan      error ("argument of %<__builtin_eh_return_regno%> must be constant");
288490075Sobrien      return constm1_rtx;
288590075Sobrien    }
288690075Sobrien
288790075Sobrien  iwhich = tree_low_cst (which, 1);
288890075Sobrien  iwhich = EH_RETURN_DATA_REGNO (iwhich);
288990075Sobrien  if (iwhich == INVALID_REGNUM)
289090075Sobrien    return constm1_rtx;
289190075Sobrien
289290075Sobrien#ifdef DWARF_FRAME_REGNUM
289390075Sobrien  iwhich = DWARF_FRAME_REGNUM (iwhich);
289490075Sobrien#else
289590075Sobrien  iwhich = DBX_REGISTER_NUMBER (iwhich);
289690075Sobrien#endif
289790075Sobrien
289890075Sobrien  return GEN_INT (iwhich);
289990075Sobrien}
290090075Sobrien
290150397Sobrien/* Given a value extracted from the return address register or stack slot,
290250397Sobrien   return the actual address encoded in that value.  */
290350397Sobrien
290450397Sobrienrtx
2905132718Skanexpand_builtin_extract_return_addr (tree addr_tree)
290650397Sobrien{
290750397Sobrien  rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
290890075Sobrien
2909117395Skan  if (GET_MODE (addr) != Pmode
2910117395Skan      && GET_MODE (addr) != VOIDmode)
2911117395Skan    {
2912117395Skan#ifdef POINTERS_EXTEND_UNSIGNED
2913117395Skan      addr = convert_memory_address (Pmode, addr);
2914117395Skan#else
2915117395Skan      addr = convert_to_mode (Pmode, addr, 0);
2916117395Skan#endif
2917117395Skan    }
2918117395Skan
291990075Sobrien  /* First mask out any unwanted bits.  */
292090075Sobrien#ifdef MASK_RETURN_ADDR
292196263Sobrien  expand_and (Pmode, addr, MASK_RETURN_ADDR, addr);
292290075Sobrien#endif
292390075Sobrien
292490075Sobrien  /* Then adjust to find the real return address.  */
292590075Sobrien#if defined (RETURN_ADDR_OFFSET)
292690075Sobrien  addr = plus_constant (addr, RETURN_ADDR_OFFSET);
292790075Sobrien#endif
292890075Sobrien
292990075Sobrien  return addr;
293050397Sobrien}
293150397Sobrien
293250397Sobrien/* Given an actual address in addr_tree, do any necessary encoding
293350397Sobrien   and return the value to be stored in the return address register or
293450397Sobrien   stack slot so the epilogue will return to that address.  */
293550397Sobrien
293650397Sobrienrtx
2937132718Skanexpand_builtin_frob_return_addr (tree addr_tree)
293850397Sobrien{
293990075Sobrien  rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, 0);
294090075Sobrien
2941132718Skan  addr = convert_memory_address (Pmode, addr);
294290075Sobrien
294350397Sobrien#ifdef RETURN_ADDR_OFFSET
294490075Sobrien  addr = force_reg (Pmode, addr);
294550397Sobrien  addr = plus_constant (addr, -RETURN_ADDR_OFFSET);
294650397Sobrien#endif
294790075Sobrien
294850397Sobrien  return addr;
294950397Sobrien}
295050397Sobrien
295190075Sobrien/* Set up the epilogue with the magic bits we'll need to return to the
295290075Sobrien   exception handler.  */
295350397Sobrien
295490075Sobrienvoid
2955132718Skanexpand_builtin_eh_return (tree stackadj_tree ATTRIBUTE_UNUSED,
2956132718Skan			  tree handler_tree)
295790075Sobrien{
2958117395Skan  rtx tmp;
295950397Sobrien
2960117395Skan#ifdef EH_RETURN_STACKADJ_RTX
2961117395Skan  tmp = expand_expr (stackadj_tree, cfun->eh->ehr_stackadj, VOIDmode, 0);
2962132718Skan  tmp = convert_memory_address (Pmode, tmp);
2963117395Skan  if (!cfun->eh->ehr_stackadj)
2964117395Skan    cfun->eh->ehr_stackadj = copy_to_reg (tmp);
2965117395Skan  else if (tmp != cfun->eh->ehr_stackadj)
2966117395Skan    emit_move_insn (cfun->eh->ehr_stackadj, tmp);
2967117395Skan#endif
296850397Sobrien
2969117395Skan  tmp = expand_expr (handler_tree, cfun->eh->ehr_handler, VOIDmode, 0);
2970132718Skan  tmp = convert_memory_address (Pmode, tmp);
2971117395Skan  if (!cfun->eh->ehr_handler)
2972117395Skan    cfun->eh->ehr_handler = copy_to_reg (tmp);
2973117395Skan  else if (tmp != cfun->eh->ehr_handler)
2974117395Skan    emit_move_insn (cfun->eh->ehr_handler, tmp);
297550397Sobrien
2976117395Skan  if (!cfun->eh->ehr_label)
2977117395Skan    cfun->eh->ehr_label = gen_label_rtx ();
297890075Sobrien  emit_jump (cfun->eh->ehr_label);
297990075Sobrien}
298090075Sobrien
298190075Sobrienvoid
2982132718Skanexpand_eh_return (void)
298390075Sobrien{
2984117395Skan  rtx around_label;
298590075Sobrien
298690075Sobrien  if (! cfun->eh->ehr_label)
298790075Sobrien    return;
298890075Sobrien
298990075Sobrien  current_function_calls_eh_return = 1;
299090075Sobrien
2991117395Skan#ifdef EH_RETURN_STACKADJ_RTX
2992117395Skan  emit_move_insn (EH_RETURN_STACKADJ_RTX, const0_rtx);
2993117395Skan#endif
2994117395Skan
299590075Sobrien  around_label = gen_label_rtx ();
299690075Sobrien  emit_jump (around_label);
299790075Sobrien
299890075Sobrien  emit_label (cfun->eh->ehr_label);
299990075Sobrien  clobber_return_register ();
300090075Sobrien
3001117395Skan#ifdef EH_RETURN_STACKADJ_RTX
3002117395Skan  emit_move_insn (EH_RETURN_STACKADJ_RTX, cfun->eh->ehr_stackadj);
3003117395Skan#endif
3004117395Skan
300590075Sobrien#ifdef HAVE_eh_return
300690075Sobrien  if (HAVE_eh_return)
3007117395Skan    emit_insn (gen_eh_return (cfun->eh->ehr_handler));
300890075Sobrien  else
300990075Sobrien#endif
301090075Sobrien    {
3011117395Skan#ifdef EH_RETURN_HANDLER_RTX
3012117395Skan      emit_move_insn (EH_RETURN_HANDLER_RTX, cfun->eh->ehr_handler);
3013117395Skan#else
3014117395Skan      error ("__builtin_eh_return not supported on this target");
3015117395Skan#endif
301650397Sobrien    }
301750397Sobrien
301890075Sobrien  emit_label (around_label);
301990075Sobrien}
3020132718Skan
3021132718Skan/* Convert a ptr_mode address ADDR_TREE to a Pmode address controlled by
3022132718Skan   POINTERS_EXTEND_UNSIGNED and return it.  */
3023132718Skan
3024132718Skanrtx
3025132718Skanexpand_builtin_extend_pointer (tree addr_tree)
3026132718Skan{
3027132718Skan  rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, 0);
3028132718Skan  int extend;
3029132718Skan
3030132718Skan#ifdef POINTERS_EXTEND_UNSIGNED
3031132718Skan  extend = POINTERS_EXTEND_UNSIGNED;
3032132718Skan#else
3033132718Skan  /* The previous EH code did an unsigned extend by default, so we do this also
3034132718Skan     for consistency.  */
3035132718Skan  extend = 1;
3036132718Skan#endif
3037132718Skan
3038132718Skan  return convert_modes (word_mode, ptr_mode, addr, extend);
3039132718Skan}
304090075Sobrien
304190075Sobrien/* In the following functions, we represent entries in the action table
304290075Sobrien   as 1-based indices.  Special cases are:
304352284Sobrien
304490075Sobrien	 0:	null action record, non-null landing pad; implies cleanups
304590075Sobrien	-1:	null action record, null landing pad; implies no action
304690075Sobrien	-2:	no call-site entry; implies must_not_throw
304790075Sobrien	-3:	we have yet to process outer regions
304852284Sobrien
304990075Sobrien   Further, no special cases apply to the "next" field of the record.
305090075Sobrien   For next, 0 means end of list.  */
305190075Sobrien
305290075Sobrienstruct action_record
305390075Sobrien{
305490075Sobrien  int offset;
305590075Sobrien  int filter;
305690075Sobrien  int next;
305790075Sobrien};
305890075Sobrien
305990075Sobrienstatic int
3060132718Skanaction_record_eq (const void *pentry, const void *pdata)
306190075Sobrien{
306290075Sobrien  const struct action_record *entry = (const struct action_record *) pentry;
306390075Sobrien  const struct action_record *data = (const struct action_record *) pdata;
306490075Sobrien  return entry->filter == data->filter && entry->next == data->next;
306550397Sobrien}
306650397Sobrien
306790075Sobrienstatic hashval_t
3068132718Skanaction_record_hash (const void *pentry)
306990075Sobrien{
307090075Sobrien  const struct action_record *entry = (const struct action_record *) pentry;
307190075Sobrien  return entry->next * 1009 + entry->filter;
307290075Sobrien}
307350397Sobrien
307490075Sobrienstatic int
3075132718Skanadd_action_record (htab_t ar_hash, int filter, int next)
307650397Sobrien{
307790075Sobrien  struct action_record **slot, *new, tmp;
307890075Sobrien
307990075Sobrien  tmp.filter = filter;
308090075Sobrien  tmp.next = next;
308190075Sobrien  slot = (struct action_record **) htab_find_slot (ar_hash, &tmp, INSERT);
308290075Sobrien
308390075Sobrien  if ((new = *slot) == NULL)
308490075Sobrien    {
3085132718Skan      new = xmalloc (sizeof (*new));
308690075Sobrien      new->offset = VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) + 1;
308790075Sobrien      new->filter = filter;
308890075Sobrien      new->next = next;
308990075Sobrien      *slot = new;
309090075Sobrien
309190075Sobrien      /* The filter value goes in untouched.  The link to the next
309290075Sobrien	 record is a "self-relative" byte offset, or zero to indicate
309390075Sobrien	 that there is no next record.  So convert the absolute 1 based
309490075Sobrien	 indices we've been carrying around into a displacement.  */
309590075Sobrien
309690075Sobrien      push_sleb128 (&cfun->eh->action_record_data, filter);
309790075Sobrien      if (next)
309890075Sobrien	next -= VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) + 1;
309990075Sobrien      push_sleb128 (&cfun->eh->action_record_data, next);
310090075Sobrien    }
310190075Sobrien
310290075Sobrien  return new->offset;
310350397Sobrien}
310450397Sobrien
310590075Sobrienstatic int
3106132718Skancollect_one_action_chain (htab_t ar_hash, struct eh_region *region)
310790075Sobrien{
310890075Sobrien  struct eh_region *c;
310990075Sobrien  int next;
311050397Sobrien
311190075Sobrien  /* If we've reached the top of the region chain, then we have
311290075Sobrien     no actions, and require no landing pad.  */
311390075Sobrien  if (region == NULL)
311490075Sobrien    return -1;
311590075Sobrien
311690075Sobrien  switch (region->type)
311790075Sobrien    {
311890075Sobrien    case ERT_CLEANUP:
311990075Sobrien      /* A cleanup adds a zero filter to the beginning of the chain, but
312090075Sobrien	 there are special cases to look out for.  If there are *only*
312190075Sobrien	 cleanups along a path, then it compresses to a zero action.
312290075Sobrien	 Further, if there are multiple cleanups along a path, we only
312390075Sobrien	 need to represent one of them, as that is enough to trigger
312490075Sobrien	 entry to the landing pad at runtime.  */
312590075Sobrien      next = collect_one_action_chain (ar_hash, region->outer);
312690075Sobrien      if (next <= 0)
312790075Sobrien	return 0;
312890075Sobrien      for (c = region->outer; c ; c = c->outer)
312990075Sobrien	if (c->type == ERT_CLEANUP)
313090075Sobrien	  return next;
313190075Sobrien      return add_action_record (ar_hash, 0, next);
313290075Sobrien
313390075Sobrien    case ERT_TRY:
313490075Sobrien      /* Process the associated catch regions in reverse order.
313590075Sobrien	 If there's a catch-all handler, then we don't need to
313690075Sobrien	 search outer regions.  Use a magic -3 value to record
313790075Sobrien	 that we haven't done the outer search.  */
313890075Sobrien      next = -3;
313990075Sobrien      for (c = region->u.try.last_catch; c ; c = c->u.catch.prev_catch)
314090075Sobrien	{
314190075Sobrien	  if (c->u.catch.type_list == NULL)
314290075Sobrien	    {
314390075Sobrien	      /* Retrieve the filter from the head of the filter list
314490075Sobrien		 where we have stored it (see assign_filter_values).  */
314590075Sobrien	      int filter
314690075Sobrien		= TREE_INT_CST_LOW (TREE_VALUE (c->u.catch.filter_list));
314790075Sobrien
314890075Sobrien	      next = add_action_record (ar_hash, filter, 0);
314990075Sobrien	    }
315090075Sobrien	  else
315190075Sobrien	    {
315290075Sobrien	      /* Once the outer search is done, trigger an action record for
315390075Sobrien                 each filter we have.  */
315490075Sobrien	      tree flt_node;
315590075Sobrien
315690075Sobrien	      if (next == -3)
315790075Sobrien		{
315890075Sobrien		  next = collect_one_action_chain (ar_hash, region->outer);
315990075Sobrien
316090075Sobrien		  /* If there is no next action, terminate the chain.  */
316190075Sobrien		  if (next == -1)
316290075Sobrien		    next = 0;
316390075Sobrien		  /* If all outer actions are cleanups or must_not_throw,
316490075Sobrien		     we'll have no action record for it, since we had wanted
316590075Sobrien		     to encode these states in the call-site record directly.
316690075Sobrien		     Add a cleanup action to the chain to catch these.  */
316790075Sobrien		  else if (next <= 0)
316890075Sobrien		    next = add_action_record (ar_hash, 0, 0);
316990075Sobrien		}
317090075Sobrien
317190075Sobrien	      flt_node = c->u.catch.filter_list;
317290075Sobrien	      for (; flt_node; flt_node = TREE_CHAIN (flt_node))
317390075Sobrien		{
317490075Sobrien		  int filter = TREE_INT_CST_LOW (TREE_VALUE (flt_node));
317590075Sobrien		  next = add_action_record (ar_hash, filter, next);
317690075Sobrien		}
317790075Sobrien	    }
317890075Sobrien	}
317990075Sobrien      return next;
318090075Sobrien
318190075Sobrien    case ERT_ALLOWED_EXCEPTIONS:
318290075Sobrien      /* An exception specification adds its filter to the
318390075Sobrien	 beginning of the chain.  */
318490075Sobrien      next = collect_one_action_chain (ar_hash, region->outer);
318590075Sobrien
3186132718Skan      /* If there is no next action, terminate the chain.  */
3187132718Skan      if (next == -1)
3188132718Skan	next = 0;
3189132718Skan      /* If all outer actions are cleanups or must_not_throw,
3190132718Skan	 we'll have no action record for it, since we had wanted
3191132718Skan	 to encode these states in the call-site record directly.
3192132718Skan	 Add a cleanup action to the chain to catch these.  */
3193132718Skan      else if (next <= 0)
3194132718Skan	next = add_action_record (ar_hash, 0, 0);
3195169689Skan
3196132718Skan      return add_action_record (ar_hash, region->u.allowed.filter, next);
3197132718Skan
319890075Sobrien    case ERT_MUST_NOT_THROW:
319990075Sobrien      /* A must-not-throw region with no inner handlers or cleanups
320090075Sobrien	 requires no call-site entry.  Note that this differs from
320190075Sobrien	 the no handler or cleanup case in that we do require an lsda
320290075Sobrien	 to be generated.  Return a magic -2 value to record this.  */
320390075Sobrien      return -2;
320490075Sobrien
320590075Sobrien    case ERT_CATCH:
320690075Sobrien    case ERT_THROW:
320790075Sobrien      /* CATCH regions are handled in TRY above.  THROW regions are
320890075Sobrien	 for optimization information only and produce no output.  */
320990075Sobrien      return collect_one_action_chain (ar_hash, region->outer);
321090075Sobrien
321190075Sobrien    default:
3212169689Skan      gcc_unreachable ();
321390075Sobrien    }
321490075Sobrien}
321590075Sobrien
321690075Sobrienstatic int
3217132718Skanadd_call_site (rtx landing_pad, int action)
321850397Sobrien{
321990075Sobrien  struct call_site_record *data = cfun->eh->call_site_data;
322090075Sobrien  int used = cfun->eh->call_site_data_used;
322190075Sobrien  int size = cfun->eh->call_site_data_size;
322250397Sobrien
322390075Sobrien  if (used >= size)
322490075Sobrien    {
322590075Sobrien      size = (size ? size * 2 : 64);
3226132718Skan      data = ggc_realloc (data, sizeof (*data) * size);
322790075Sobrien      cfun->eh->call_site_data = data;
322890075Sobrien      cfun->eh->call_site_data_size = size;
322990075Sobrien    }
323090075Sobrien
323190075Sobrien  data[used].landing_pad = landing_pad;
323290075Sobrien  data[used].action = action;
323390075Sobrien
323490075Sobrien  cfun->eh->call_site_data_used = used + 1;
323590075Sobrien
323690075Sobrien  return used + call_site_base;
323750397Sobrien}
323850397Sobrien
323990075Sobrien/* Turn REG_EH_REGION notes back into NOTE_INSN_EH_REGION notes.
324090075Sobrien   The new note numbers will not refer to region numbers, but
324190075Sobrien   instead to call site entries.  */
324290075Sobrien
3243169689Skanunsigned int
3244132718Skanconvert_to_eh_region_ranges (void)
324550397Sobrien{
324690075Sobrien  rtx insn, iter, note;
324790075Sobrien  htab_t ar_hash;
324890075Sobrien  int last_action = -3;
324990075Sobrien  rtx last_action_insn = NULL_RTX;
325090075Sobrien  rtx last_landing_pad = NULL_RTX;
325190075Sobrien  rtx first_no_action_insn = NULL_RTX;
325290075Sobrien  int call_site = 0;
325350397Sobrien
325490075Sobrien  if (USING_SJLJ_EXCEPTIONS || cfun->eh->region_tree == NULL)
3255169689Skan    return 0;
325650397Sobrien
325790075Sobrien  VARRAY_UCHAR_INIT (cfun->eh->action_record_data, 64, "action_record_data");
325850397Sobrien
325990075Sobrien  ar_hash = htab_create (31, action_record_hash, action_record_eq, free);
326050397Sobrien
326190075Sobrien  for (iter = get_insns (); iter ; iter = NEXT_INSN (iter))
326290075Sobrien    if (INSN_P (iter))
326390075Sobrien      {
326490075Sobrien	struct eh_region *region;
326590075Sobrien	int this_action;
326690075Sobrien	rtx this_landing_pad;
326750397Sobrien
326890075Sobrien	insn = iter;
3269169689Skan	if (NONJUMP_INSN_P (insn)
327090075Sobrien	    && GET_CODE (PATTERN (insn)) == SEQUENCE)
327190075Sobrien	  insn = XVECEXP (PATTERN (insn), 0, 0);
327250397Sobrien
327390075Sobrien	note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
327490075Sobrien	if (!note)
327590075Sobrien	  {
3276169689Skan	    if (! (CALL_P (insn)
327790075Sobrien		   || (flag_non_call_exceptions
327890075Sobrien		       && may_trap_p (PATTERN (insn)))))
327990075Sobrien	      continue;
328090075Sobrien	    this_action = -1;
328190075Sobrien	    region = NULL;
328290075Sobrien	  }
328390075Sobrien	else
328490075Sobrien	  {
328590075Sobrien	    if (INTVAL (XEXP (note, 0)) <= 0)
328690075Sobrien	      continue;
3287169689Skan	    region = VEC_index (eh_region, cfun->eh->region_array, INTVAL (XEXP (note, 0)));
328890075Sobrien	    this_action = collect_one_action_chain (ar_hash, region);
328990075Sobrien	  }
329050397Sobrien
329190075Sobrien	/* Existence of catch handlers, or must-not-throw regions
329290075Sobrien	   implies that an lsda is needed (even if empty).  */
329390075Sobrien	if (this_action != -1)
329490075Sobrien	  cfun->uses_eh_lsda = 1;
329550397Sobrien
329690075Sobrien	/* Delay creation of region notes for no-action regions
329790075Sobrien	   until we're sure that an lsda will be required.  */
329890075Sobrien	else if (last_action == -3)
329990075Sobrien	  {
330090075Sobrien	    first_no_action_insn = iter;
330190075Sobrien	    last_action = -1;
330290075Sobrien	  }
330350397Sobrien
330490075Sobrien	/* Cleanups and handlers may share action chains but not
330590075Sobrien	   landing pads.  Collect the landing pad for this region.  */
330690075Sobrien	if (this_action >= 0)
330790075Sobrien	  {
330890075Sobrien	    struct eh_region *o;
330990075Sobrien	    for (o = region; ! o->landing_pad ; o = o->outer)
331090075Sobrien	      continue;
331190075Sobrien	    this_landing_pad = o->landing_pad;
331290075Sobrien	  }
331390075Sobrien	else
331490075Sobrien	  this_landing_pad = NULL_RTX;
331550397Sobrien
331690075Sobrien	/* Differing actions or landing pads implies a change in call-site
331790075Sobrien	   info, which implies some EH_REGION note should be emitted.  */
331890075Sobrien	if (last_action != this_action
331990075Sobrien	    || last_landing_pad != this_landing_pad)
332090075Sobrien	  {
332190075Sobrien	    /* If we'd not seen a previous action (-3) or the previous
332290075Sobrien	       action was must-not-throw (-2), then we do not need an
332390075Sobrien	       end note.  */
332490075Sobrien	    if (last_action >= -1)
332590075Sobrien	      {
332690075Sobrien		/* If we delayed the creation of the begin, do it now.  */
332790075Sobrien		if (first_no_action_insn)
332890075Sobrien		  {
332990075Sobrien		    call_site = add_call_site (NULL_RTX, 0);
333090075Sobrien		    note = emit_note_before (NOTE_INSN_EH_REGION_BEG,
333190075Sobrien					     first_no_action_insn);
333290075Sobrien		    NOTE_EH_HANDLER (note) = call_site;
333390075Sobrien		    first_no_action_insn = NULL_RTX;
333490075Sobrien		  }
333550397Sobrien
333690075Sobrien		note = emit_note_after (NOTE_INSN_EH_REGION_END,
333790075Sobrien					last_action_insn);
333890075Sobrien		NOTE_EH_HANDLER (note) = call_site;
333990075Sobrien	      }
334052284Sobrien
334190075Sobrien	    /* If the new action is must-not-throw, then no region notes
334290075Sobrien	       are created.  */
334390075Sobrien	    if (this_action >= -1)
334490075Sobrien	      {
334590075Sobrien		call_site = add_call_site (this_landing_pad,
334690075Sobrien					   this_action < 0 ? 0 : this_action);
334790075Sobrien		note = emit_note_before (NOTE_INSN_EH_REGION_BEG, iter);
334890075Sobrien		NOTE_EH_HANDLER (note) = call_site;
334990075Sobrien	      }
335052284Sobrien
335190075Sobrien	    last_action = this_action;
335290075Sobrien	    last_landing_pad = this_landing_pad;
335390075Sobrien	  }
335490075Sobrien	last_action_insn = iter;
335590075Sobrien      }
335652284Sobrien
335790075Sobrien  if (last_action >= -1 && ! first_no_action_insn)
335890075Sobrien    {
335990075Sobrien      note = emit_note_after (NOTE_INSN_EH_REGION_END, last_action_insn);
336090075Sobrien      NOTE_EH_HANDLER (note) = call_site;
336190075Sobrien    }
336252284Sobrien
336390075Sobrien  htab_delete (ar_hash);
3364169689Skan  return 0;
336550397Sobrien}
336690075Sobrien
3367169689Skanstruct tree_opt_pass pass_convert_to_eh_region_ranges =
3368169689Skan{
3369169689Skan  "eh-ranges",                          /* name */
3370169689Skan  NULL,                                 /* gate */
3371169689Skan  convert_to_eh_region_ranges,          /* execute */
3372169689Skan  NULL,                                 /* sub */
3373169689Skan  NULL,                                 /* next */
3374169689Skan  0,                                    /* static_pass_number */
3375169689Skan  0,                                    /* tv_id */
3376169689Skan  0,                                    /* properties_required */
3377169689Skan  0,                                    /* properties_provided */
3378169689Skan  0,                                    /* properties_destroyed */
3379169689Skan  0,                                    /* todo_flags_start */
3380169689Skan  TODO_dump_func,			/* todo_flags_finish */
3381169689Skan  0                                     /* letter */
3382169689Skan};
3383169689Skan
338450397Sobrien
338590075Sobrienstatic void
3386132718Skanpush_uleb128 (varray_type *data_area, unsigned int value)
338790075Sobrien{
338890075Sobrien  do
338990075Sobrien    {
339090075Sobrien      unsigned char byte = value & 0x7f;
339190075Sobrien      value >>= 7;
339290075Sobrien      if (value)
339390075Sobrien	byte |= 0x80;
339490075Sobrien      VARRAY_PUSH_UCHAR (*data_area, byte);
339590075Sobrien    }
339690075Sobrien  while (value);
339790075Sobrien}
339850397Sobrien
339990075Sobrienstatic void
3400132718Skanpush_sleb128 (varray_type *data_area, int value)
340190075Sobrien{
340290075Sobrien  unsigned char byte;
340390075Sobrien  int more;
340450397Sobrien
340590075Sobrien  do
340690075Sobrien    {
340790075Sobrien      byte = value & 0x7f;
340890075Sobrien      value >>= 7;
340990075Sobrien      more = ! ((value == 0 && (byte & 0x40) == 0)
341090075Sobrien		|| (value == -1 && (byte & 0x40) != 0));
341190075Sobrien      if (more)
341290075Sobrien	byte |= 0x80;
341390075Sobrien      VARRAY_PUSH_UCHAR (*data_area, byte);
341490075Sobrien    }
341590075Sobrien  while (more);
341690075Sobrien}
341750397Sobrien
341890075Sobrien
341990075Sobrien#ifndef HAVE_AS_LEB128
342090075Sobrienstatic int
3421132718Skandw2_size_of_call_site_table (void)
342250397Sobrien{
342390075Sobrien  int n = cfun->eh->call_site_data_used;
342490075Sobrien  int size = n * (4 + 4 + 4);
342590075Sobrien  int i;
342650397Sobrien
342790075Sobrien  for (i = 0; i < n; ++i)
342850397Sobrien    {
342990075Sobrien      struct call_site_record *cs = &cfun->eh->call_site_data[i];
343090075Sobrien      size += size_of_uleb128 (cs->action);
343150397Sobrien    }
343290075Sobrien
343390075Sobrien  return size;
343450397Sobrien}
343550397Sobrien
343690075Sobrienstatic int
3437132718Skansjlj_size_of_call_site_table (void)
343890075Sobrien{
343990075Sobrien  int n = cfun->eh->call_site_data_used;
344090075Sobrien  int size = 0;
344190075Sobrien  int i;
344250397Sobrien
344390075Sobrien  for (i = 0; i < n; ++i)
344490075Sobrien    {
344590075Sobrien      struct call_site_record *cs = &cfun->eh->call_site_data[i];
344690075Sobrien      size += size_of_uleb128 (INTVAL (cs->landing_pad));
344790075Sobrien      size += size_of_uleb128 (cs->action);
344890075Sobrien    }
344990075Sobrien
345090075Sobrien  return size;
345190075Sobrien}
345290075Sobrien#endif
345390075Sobrien
345490075Sobrienstatic void
3455132718Skandw2_output_call_site_table (void)
345650397Sobrien{
345790075Sobrien  int n = cfun->eh->call_site_data_used;
345890075Sobrien  int i;
345950397Sobrien
346090075Sobrien  for (i = 0; i < n; ++i)
346150397Sobrien    {
346290075Sobrien      struct call_site_record *cs = &cfun->eh->call_site_data[i];
346390075Sobrien      char reg_start_lab[32];
346490075Sobrien      char reg_end_lab[32];
346590075Sobrien      char landing_pad_lab[32];
346690075Sobrien
346790075Sobrien      ASM_GENERATE_INTERNAL_LABEL (reg_start_lab, "LEHB", call_site_base + i);
346890075Sobrien      ASM_GENERATE_INTERNAL_LABEL (reg_end_lab, "LEHE", call_site_base + i);
346990075Sobrien
347090075Sobrien      if (cs->landing_pad)
347190075Sobrien	ASM_GENERATE_INTERNAL_LABEL (landing_pad_lab, "L",
347290075Sobrien				     CODE_LABEL_NUMBER (cs->landing_pad));
347390075Sobrien
347490075Sobrien      /* ??? Perhaps use insn length scaling if the assembler supports
347590075Sobrien	 generic arithmetic.  */
347690075Sobrien      /* ??? Perhaps use attr_length to choose data1 or data2 instead of
347790075Sobrien	 data4 if the function is small enough.  */
347890075Sobrien#ifdef HAVE_AS_LEB128
3479169689Skan      dw2_asm_output_delta_uleb128 (reg_start_lab,
3480169689Skan				    current_function_func_begin_label,
348190075Sobrien				    "region %d start", i);
348290075Sobrien      dw2_asm_output_delta_uleb128 (reg_end_lab, reg_start_lab,
348390075Sobrien				    "length");
348490075Sobrien      if (cs->landing_pad)
3485169689Skan	dw2_asm_output_delta_uleb128 (landing_pad_lab,
3486169689Skan				      current_function_func_begin_label,
348790075Sobrien				      "landing pad");
348890075Sobrien      else
348990075Sobrien	dw2_asm_output_data_uleb128 (0, "landing pad");
349090075Sobrien#else
3491169689Skan      dw2_asm_output_delta (4, reg_start_lab,
3492169689Skan			    current_function_func_begin_label,
349390075Sobrien			    "region %d start", i);
349490075Sobrien      dw2_asm_output_delta (4, reg_end_lab, reg_start_lab, "length");
349590075Sobrien      if (cs->landing_pad)
3496169689Skan	dw2_asm_output_delta (4, landing_pad_lab,
3497169689Skan			      current_function_func_begin_label,
349890075Sobrien			      "landing pad");
349990075Sobrien      else
350090075Sobrien	dw2_asm_output_data (4, 0, "landing pad");
350190075Sobrien#endif
350290075Sobrien      dw2_asm_output_data_uleb128 (cs->action, "action");
350350397Sobrien    }
350490075Sobrien
350590075Sobrien  call_site_base += n;
350650397Sobrien}
350750397Sobrien
350890075Sobrienstatic void
3509132718Skansjlj_output_call_site_table (void)
351090075Sobrien{
351190075Sobrien  int n = cfun->eh->call_site_data_used;
351290075Sobrien  int i;
351350397Sobrien
351490075Sobrien  for (i = 0; i < n; ++i)
351590075Sobrien    {
351690075Sobrien      struct call_site_record *cs = &cfun->eh->call_site_data[i];
351790075Sobrien
351890075Sobrien      dw2_asm_output_data_uleb128 (INTVAL (cs->landing_pad),
351990075Sobrien				   "region %d landing pad", i);
352090075Sobrien      dw2_asm_output_data_uleb128 (cs->action, "action");
352190075Sobrien    }
352290075Sobrien
352390075Sobrien  call_site_base += n;
352490075Sobrien}
352590075Sobrien
3526169689Skan#ifndef TARGET_UNWIND_INFO
3527169689Skan/* Switch to the section that should be used for exception tables.  */
3528117395Skan
3529169689Skanstatic void
3530169689Skanswitch_to_exception_section (void)
3531117395Skan{
3532169689Skan  if (exception_section == 0)
3533117395Skan    {
3534169689Skan      if (targetm.have_named_sections)
3535169689Skan	{
3536169689Skan	  int flags;
3537117395Skan
3538169689Skan	  if (EH_TABLES_CAN_BE_READ_ONLY)
3539169689Skan	    {
3540169689Skan	      int tt_format =
3541169689Skan		ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
3542169689Skan	      flags = ((! flag_pic
3543169689Skan			|| ((tt_format & 0x70) != DW_EH_PE_absptr
3544169689Skan			    && (tt_format & 0x70) != DW_EH_PE_aligned))
3545169689Skan		       ? 0 : SECTION_WRITE);
3546169689Skan	    }
3547169689Skan	  else
3548169689Skan	    flags = SECTION_WRITE;
3549169689Skan	  exception_section = get_section (".gcc_except_table", flags, NULL);
3550169689Skan	}
3551169689Skan      else
3552169689Skan	exception_section = flag_pic ? data_section : readonly_data_section;
3553169689Skan    }
3554169689Skan  switch_to_section (exception_section);
3555169689Skan}
3556117395Skan#endif
3557169689Skan
3558169689Skan
3559169689Skan/* Output a reference from an exception table to the type_info object TYPE.
3560169689Skan   TT_FORMAT and TT_FORMAT_SIZE describe the DWARF encoding method used for
3561169689Skan   the value.  */
3562169689Skan
3563169689Skanstatic void
3564169689Skanoutput_ttype (tree type, int tt_format, int tt_format_size)
3565169689Skan{
3566169689Skan  rtx value;
3567169689Skan  bool public = true;
3568169689Skan
3569169689Skan  if (type == NULL_TREE)
3570169689Skan    value = const0_rtx;
3571169689Skan  else
3572169689Skan    {
3573169689Skan      struct cgraph_varpool_node *node;
3574169689Skan
3575169689Skan      type = lookup_type_for_runtime (type);
3576169689Skan      value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
3577169689Skan
3578169689Skan      /* Let cgraph know that the rtti decl is used.  Not all of the
3579169689Skan	 paths below go through assemble_integer, which would take
3580169689Skan	 care of this for us.  */
3581169689Skan      STRIP_NOPS (type);
3582169689Skan      if (TREE_CODE (type) == ADDR_EXPR)
3583169689Skan	{
3584169689Skan	  type = TREE_OPERAND (type, 0);
3585169689Skan	  if (TREE_CODE (type) == VAR_DECL)
3586169689Skan	    {
3587169689Skan	      node = cgraph_varpool_node (type);
3588169689Skan	      if (node)
3589169689Skan		cgraph_varpool_mark_needed_node (node);
3590169689Skan	      public = TREE_PUBLIC (type);
3591169689Skan	    }
3592169689Skan	}
3593169689Skan      else
3594169689Skan	gcc_assert (TREE_CODE (type) == INTEGER_CST);
3595117395Skan    }
3596169689Skan
3597169689Skan  /* Allow the target to override the type table entry format.  */
3598169689Skan  if (targetm.asm_out.ttype (value))
3599169689Skan    return;
3600169689Skan
3601169689Skan  if (tt_format == DW_EH_PE_absptr || tt_format == DW_EH_PE_aligned)
3602169689Skan    assemble_integer (value, tt_format_size,
3603169689Skan		      tt_format_size * BITS_PER_UNIT, 1);
3604117395Skan  else
3605169689Skan    dw2_asm_output_encoded_addr_rtx (tt_format, value, public, NULL);
3606117395Skan}
3607117395Skan
3608117395Skanvoid
3609132718Skanoutput_function_exception_table (void)
361050397Sobrien{
361190075Sobrien  int tt_format, cs_format, lp_format, i, n;
361290075Sobrien#ifdef HAVE_AS_LEB128
361390075Sobrien  char ttype_label[32];
361490075Sobrien  char cs_after_size_label[32];
361590075Sobrien  char cs_end_label[32];
361690075Sobrien#else
361790075Sobrien  int call_site_len;
361890075Sobrien#endif
361990075Sobrien  int have_tt_data;
362090075Sobrien  int tt_format_size = 0;
362150397Sobrien
3622169689Skan  if (eh_personality_libfunc)
3623169689Skan    assemble_external_libcall (eh_personality_libfunc);
3624169689Skan
362590075Sobrien  /* Not all functions need anything.  */
362690075Sobrien  if (! cfun->uses_eh_lsda)
362750397Sobrien    return;
362850397Sobrien
3629169689Skan#ifdef TARGET_UNWIND_INFO
3630169689Skan  /* TODO: Move this into target file.  */
363190075Sobrien  fputs ("\t.personality\t", asm_out_file);
363290075Sobrien  output_addr_const (asm_out_file, eh_personality_libfunc);
363390075Sobrien  fputs ("\n\t.handlerdata\n", asm_out_file);
363490075Sobrien  /* Note that varasm still thinks we're in the function's code section.
363590075Sobrien     The ".endp" directive that will immediately follow will take us back.  */
363690075Sobrien#else
3637169689Skan  switch_to_exception_section ();
363890075Sobrien#endif
363950397Sobrien
3640169689Skan  /* If the target wants a label to begin the table, emit it here.  */
3641169689Skan  targetm.asm_out.except_table_label (asm_out_file);
3642169689Skan
3643169689Skan  have_tt_data = (VEC_length (tree, cfun->eh->ttype_data) > 0
364490075Sobrien		  || VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) > 0);
364550397Sobrien
364690075Sobrien  /* Indicate the format of the @TType entries.  */
364790075Sobrien  if (! have_tt_data)
364890075Sobrien    tt_format = DW_EH_PE_omit;
364990075Sobrien  else
365090075Sobrien    {
365190075Sobrien      tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
365290075Sobrien#ifdef HAVE_AS_LEB128
3653117395Skan      ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT",
3654117395Skan				   current_function_funcdef_no);
365590075Sobrien#endif
365690075Sobrien      tt_format_size = size_of_encoded_value (tt_format);
365750397Sobrien
365890075Sobrien      assemble_align (tt_format_size * BITS_PER_UNIT);
365990075Sobrien    }
366050397Sobrien
3661169689Skan  targetm.asm_out.internal_label (asm_out_file, "LLSDA",
3662117395Skan			     current_function_funcdef_no);
366350397Sobrien
366490075Sobrien  /* The LSDA header.  */
366550397Sobrien
366690075Sobrien  /* Indicate the format of the landing pad start pointer.  An omitted
366790075Sobrien     field implies @LPStart == @Start.  */
366890075Sobrien  /* Currently we always put @LPStart == @Start.  This field would
366990075Sobrien     be most useful in moving the landing pads completely out of
367090075Sobrien     line to another section, but it could also be used to minimize
367190075Sobrien     the size of uleb128 landing pad offsets.  */
367290075Sobrien  lp_format = DW_EH_PE_omit;
367390075Sobrien  dw2_asm_output_data (1, lp_format, "@LPStart format (%s)",
367490075Sobrien		       eh_data_format_name (lp_format));
367550397Sobrien
367690075Sobrien  /* @LPStart pointer would go here.  */
367750397Sobrien
367890075Sobrien  dw2_asm_output_data (1, tt_format, "@TType format (%s)",
367990075Sobrien		       eh_data_format_name (tt_format));
368050397Sobrien
368190075Sobrien#ifndef HAVE_AS_LEB128
368290075Sobrien  if (USING_SJLJ_EXCEPTIONS)
368390075Sobrien    call_site_len = sjlj_size_of_call_site_table ();
368490075Sobrien  else
368590075Sobrien    call_site_len = dw2_size_of_call_site_table ();
368690075Sobrien#endif
368790075Sobrien
368890075Sobrien  /* A pc-relative 4-byte displacement to the @TType data.  */
368990075Sobrien  if (have_tt_data)
369090075Sobrien    {
369190075Sobrien#ifdef HAVE_AS_LEB128
369290075Sobrien      char ttype_after_disp_label[32];
369390075Sobrien      ASM_GENERATE_INTERNAL_LABEL (ttype_after_disp_label, "LLSDATTD",
3694117395Skan				   current_function_funcdef_no);
369590075Sobrien      dw2_asm_output_delta_uleb128 (ttype_label, ttype_after_disp_label,
369690075Sobrien				    "@TType base offset");
369790075Sobrien      ASM_OUTPUT_LABEL (asm_out_file, ttype_after_disp_label);
369890075Sobrien#else
369990075Sobrien      /* Ug.  Alignment queers things.  */
370090075Sobrien      unsigned int before_disp, after_disp, last_disp, disp;
370190075Sobrien
370290075Sobrien      before_disp = 1 + 1;
370390075Sobrien      after_disp = (1 + size_of_uleb128 (call_site_len)
370490075Sobrien		    + call_site_len
370590075Sobrien		    + VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data)
3706169689Skan		    + (VEC_length (tree, cfun->eh->ttype_data)
370790075Sobrien		       * tt_format_size));
370890075Sobrien
370990075Sobrien      disp = after_disp;
371090075Sobrien      do
371190075Sobrien	{
371290075Sobrien	  unsigned int disp_size, pad;
371390075Sobrien
371490075Sobrien	  last_disp = disp;
371590075Sobrien	  disp_size = size_of_uleb128 (disp);
371690075Sobrien	  pad = before_disp + disp_size + after_disp;
371790075Sobrien	  if (pad % tt_format_size)
371890075Sobrien	    pad = tt_format_size - (pad % tt_format_size);
371990075Sobrien	  else
372090075Sobrien	    pad = 0;
372190075Sobrien	  disp = after_disp + pad;
372290075Sobrien	}
372390075Sobrien      while (disp != last_disp);
372490075Sobrien
372590075Sobrien      dw2_asm_output_data_uleb128 (disp, "@TType base offset");
372690075Sobrien#endif
372790075Sobrien    }
372890075Sobrien
372990075Sobrien  /* Indicate the format of the call-site offsets.  */
373090075Sobrien#ifdef HAVE_AS_LEB128
373190075Sobrien  cs_format = DW_EH_PE_uleb128;
373290075Sobrien#else
373390075Sobrien  cs_format = DW_EH_PE_udata4;
373490075Sobrien#endif
373590075Sobrien  dw2_asm_output_data (1, cs_format, "call-site format (%s)",
373690075Sobrien		       eh_data_format_name (cs_format));
373790075Sobrien
373890075Sobrien#ifdef HAVE_AS_LEB128
373990075Sobrien  ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label, "LLSDACSB",
3740117395Skan			       current_function_funcdef_no);
374190075Sobrien  ASM_GENERATE_INTERNAL_LABEL (cs_end_label, "LLSDACSE",
3742117395Skan			       current_function_funcdef_no);
374390075Sobrien  dw2_asm_output_delta_uleb128 (cs_end_label, cs_after_size_label,
374490075Sobrien				"Call-site table length");
374590075Sobrien  ASM_OUTPUT_LABEL (asm_out_file, cs_after_size_label);
374690075Sobrien  if (USING_SJLJ_EXCEPTIONS)
374790075Sobrien    sjlj_output_call_site_table ();
374890075Sobrien  else
374990075Sobrien    dw2_output_call_site_table ();
375090075Sobrien  ASM_OUTPUT_LABEL (asm_out_file, cs_end_label);
375190075Sobrien#else
375290075Sobrien  dw2_asm_output_data_uleb128 (call_site_len,"Call-site table length");
375390075Sobrien  if (USING_SJLJ_EXCEPTIONS)
375490075Sobrien    sjlj_output_call_site_table ();
375590075Sobrien  else
375690075Sobrien    dw2_output_call_site_table ();
375790075Sobrien#endif
375890075Sobrien
375990075Sobrien  /* ??? Decode and interpret the data for flag_debug_asm.  */
376090075Sobrien  n = VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data);
376190075Sobrien  for (i = 0; i < n; ++i)
376290075Sobrien    dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->action_record_data, i),
376390075Sobrien			 (i ? NULL : "Action record table"));
376490075Sobrien
376590075Sobrien  if (have_tt_data)
376690075Sobrien    assemble_align (tt_format_size * BITS_PER_UNIT);
376790075Sobrien
3768169689Skan  i = VEC_length (tree, cfun->eh->ttype_data);
376990075Sobrien  while (i-- > 0)
377090075Sobrien    {
3771169689Skan      tree type = VEC_index (tree, cfun->eh->ttype_data, i);
3772169689Skan      output_ttype (type, tt_format, tt_format_size);
377390075Sobrien    }
377490075Sobrien
377590075Sobrien#ifdef HAVE_AS_LEB128
377690075Sobrien  if (have_tt_data)
377790075Sobrien      ASM_OUTPUT_LABEL (asm_out_file, ttype_label);
377890075Sobrien#endif
377990075Sobrien
378090075Sobrien  /* ??? Decode and interpret the data for flag_debug_asm.  */
378190075Sobrien  n = VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data);
378290075Sobrien  for (i = 0; i < n; ++i)
3783169689Skan    {
3784169689Skan      if (targetm.arm_eabi_unwinder)
3785169689Skan	{
3786169689Skan	  tree type = VARRAY_TREE (cfun->eh->ehspec_data, i);
3787169689Skan	  output_ttype (type, tt_format, tt_format_size);
3788169689Skan	}
3789169689Skan      else
3790169689Skan	dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->ehspec_data, i),
3791169689Skan			     (i ? NULL : "Exception specification table"));
3792169689Skan    }
379390075Sobrien
3794169689Skan  switch_to_section (current_function_section ());
3795117395Skan}
379690075Sobrien
3797169689Skanvoid
3798169689Skanset_eh_throw_stmt_table (struct function *fun, struct htab *table)
3799169689Skan{
3800169689Skan  fun->eh->throw_stmt_table = table;
3801169689Skan}
3802169689Skan
3803169689Skanhtab_t
3804169689Skanget_eh_throw_stmt_table (struct function *fun)
3805169689Skan{
3806169689Skan  return fun->eh->throw_stmt_table;
3807169689Skan}
3808169689Skan
3809169689Skan/* Dump EH information to OUT.  */
3810169689Skanvoid
3811169689Skandump_eh_tree (FILE *out, struct function *fun)
3812169689Skan{
3813169689Skan  struct eh_region *i;
3814169689Skan  int depth = 0;
3815169689Skan  static const char * const type_name[] = {"unknown", "cleanup", "try", "catch",
3816169689Skan					   "allowed_exceptions", "must_not_throw",
3817169689Skan					   "throw"};
3818169689Skan
3819169689Skan  i = fun->eh->region_tree;
3820169689Skan  if (! i)
3821169689Skan    return;
3822169689Skan
3823169689Skan  fprintf (out, "Eh tree:\n");
3824169689Skan  while (1)
3825169689Skan    {
3826169689Skan      fprintf (out, "  %*s %i %s", depth * 2, "",
3827169689Skan	       i->region_number, type_name [(int)i->type]);
3828169689Skan      if (i->tree_label)
3829169689Skan	{
3830169689Skan          fprintf (out, " tree_label:");
3831169689Skan	  print_generic_expr (out, i->tree_label, 0);
3832169689Skan	}
3833169689Skan      fprintf (out, "\n");
3834169689Skan      /* If there are sub-regions, process them.  */
3835169689Skan      if (i->inner)
3836169689Skan	i = i->inner, depth++;
3837169689Skan      /* If there are peers, process them.  */
3838169689Skan      else if (i->next_peer)
3839169689Skan	i = i->next_peer;
3840169689Skan      /* Otherwise, step back up the tree to the next peer.  */
3841169689Skan      else
3842169689Skan	{
3843169689Skan	  do {
3844169689Skan	    i = i->outer;
3845169689Skan	    depth--;
3846169689Skan	    if (i == NULL)
3847169689Skan	      return;
3848169689Skan	  } while (i->next_peer == NULL);
3849169689Skan	  i = i->next_peer;
3850169689Skan	}
3851169689Skan    }
3852169689Skan}
3853169689Skan
3854169689Skan/* Verify some basic invariants on EH datastructures.  Could be extended to
3855169689Skan   catch more.  */
3856169689Skanvoid
3857169689Skanverify_eh_tree (struct function *fun)
3858169689Skan{
3859169689Skan  struct eh_region *i, *outer = NULL;
3860169689Skan  bool err = false;
3861169689Skan  int nvisited = 0;
3862169689Skan  int count = 0;
3863169689Skan  int j;
3864169689Skan  int depth = 0;
3865169689Skan
3866169689Skan  i = fun->eh->region_tree;
3867169689Skan  if (! i)
3868169689Skan    return;
3869169689Skan  for (j = fun->eh->last_region_number; j > 0; --j)
3870169689Skan    if ((i = VEC_index (eh_region, cfun->eh->region_array, j)))
3871169689Skan      {
3872169689Skan	count++;
3873169689Skan	if (i->region_number != j)
3874169689Skan	  {
3875169689Skan	    error ("region_array is corrupted for region %i", i->region_number);
3876169689Skan	    err = true;
3877169689Skan	  }
3878169689Skan      }
3879169689Skan
3880169689Skan  while (1)
3881169689Skan    {
3882169689Skan      if (VEC_index (eh_region, cfun->eh->region_array, i->region_number) != i)
3883169689Skan	{
3884169689Skan	  error ("region_array is corrupted for region %i", i->region_number);
3885169689Skan	  err = true;
3886169689Skan	}
3887169689Skan      if (i->outer != outer)
3888169689Skan	{
3889169689Skan	  error ("outer block of region %i is wrong", i->region_number);
3890169689Skan	  err = true;
3891169689Skan	}
3892169689Skan      if (i->may_contain_throw && outer && !outer->may_contain_throw)
3893169689Skan	{
3894169689Skan	  error ("region %i may contain throw and is contained in region that may not",
3895169689Skan		 i->region_number);
3896169689Skan	  err = true;
3897169689Skan	}
3898169689Skan      if (depth < 0)
3899169689Skan	{
3900169689Skan	  error ("negative nesting depth of region %i", i->region_number);
3901169689Skan	  err = true;
3902169689Skan	}
3903169689Skan      nvisited ++;
3904169689Skan      /* If there are sub-regions, process them.  */
3905169689Skan      if (i->inner)
3906169689Skan	outer = i, i = i->inner, depth++;
3907169689Skan      /* If there are peers, process them.  */
3908169689Skan      else if (i->next_peer)
3909169689Skan	i = i->next_peer;
3910169689Skan      /* Otherwise, step back up the tree to the next peer.  */
3911169689Skan      else
3912169689Skan	{
3913169689Skan	  do {
3914169689Skan	    i = i->outer;
3915169689Skan	    depth--;
3916169689Skan	    if (i == NULL)
3917169689Skan	      {
3918169689Skan		if (depth != -1)
3919169689Skan		  {
3920169689Skan		    error ("tree list ends on depth %i", depth + 1);
3921169689Skan		    err = true;
3922169689Skan		  }
3923169689Skan		if (count != nvisited)
3924169689Skan		  {
3925169689Skan		    error ("array does not match the region tree");
3926169689Skan		    err = true;
3927169689Skan		  }
3928169689Skan		if (err)
3929169689Skan		  {
3930169689Skan		    dump_eh_tree (stderr, fun);
3931169689Skan		    internal_error ("verify_eh_tree failed");
3932169689Skan		  }
3933169689Skan	        return;
3934169689Skan	      }
3935169689Skan	    outer = i->outer;
3936169689Skan	  } while (i->next_peer == NULL);
3937169689Skan	  i = i->next_peer;
3938169689Skan	}
3939169689Skan    }
3940169689Skan}
3941169689Skan
3942169689Skan/* Initialize unwind_resume_libfunc.  */
3943169689Skan
3944169689Skanvoid
3945169689Skandefault_init_unwind_resume_libfunc (void)
3946169689Skan{
3947169689Skan  /* The default c++ routines aren't actually c++ specific, so use those.  */
3948169689Skan  unwind_resume_libfunc =
3949169689Skan    init_one_libfunc ( USING_SJLJ_EXCEPTIONS ? "_Unwind_SjLj_Resume"
3950169689Skan					     : "_Unwind_Resume");
3951169689Skan}
3952169689Skan
3953169689Skan
3954169689Skanstatic bool
3955169689Skangate_handle_eh (void)
3956169689Skan{
3957169689Skan  return doing_eh (0);
3958169689Skan}
3959169689Skan
3960169689Skan/* Complete generation of exception handling code.  */
3961169689Skanstatic unsigned int
3962169689Skanrest_of_handle_eh (void)
3963169689Skan{
3964169689Skan  cleanup_cfg (CLEANUP_NO_INSN_DEL);
3965169689Skan  finish_eh_generation ();
3966169689Skan  cleanup_cfg (CLEANUP_NO_INSN_DEL);
3967169689Skan  return 0;
3968169689Skan}
3969169689Skan
3970169689Skanstruct tree_opt_pass pass_rtl_eh =
3971169689Skan{
3972169689Skan  "eh",                                 /* name */
3973169689Skan  gate_handle_eh,                       /* gate */
3974169689Skan  rest_of_handle_eh,			/* execute */
3975169689Skan  NULL,                                 /* sub */
3976169689Skan  NULL,                                 /* next */
3977169689Skan  0,                                    /* static_pass_number */
3978169689Skan  TV_JUMP,                              /* tv_id */
3979169689Skan  0,                                    /* properties_required */
3980169689Skan  0,                                    /* properties_provided */
3981169689Skan  0,                                    /* properties_destroyed */
3982169689Skan  0,                                    /* todo_flags_start */
3983169689Skan  TODO_dump_func,                       /* todo_flags_finish */
3984169689Skan  'h'                                   /* letter */
3985169689Skan};
3986169689Skan
3987117395Skan#include "gt-except.h"
3988