except.c revision 96263
150397Sobrien/* Implements exception handling.
290075Sobrien   Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
390075Sobrien   1999, 2000, 2001, 2002 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
2090075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
2190075Sobrien02111-1307, 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"
5290075Sobrien#include "rtl.h"
5390075Sobrien#include "tree.h"
5490075Sobrien#include "flags.h"
5590075Sobrien#include "function.h"
5690075Sobrien#include "expr.h"
5790075Sobrien#include "libfuncs.h"
5890075Sobrien#include "insn-config.h"
5990075Sobrien#include "except.h"
6090075Sobrien#include "integrate.h"
6190075Sobrien#include "hard-reg-set.h"
6290075Sobrien#include "basic-block.h"
6390075Sobrien#include "output.h"
6490075Sobrien#include "dwarf2asm.h"
6590075Sobrien#include "dwarf2out.h"
6690075Sobrien#include "dwarf2.h"
6790075Sobrien#include "toplev.h"
6890075Sobrien#include "hashtab.h"
6990075Sobrien#include "intl.h"
7090075Sobrien#include "ggc.h"
7190075Sobrien#include "tm_p.h"
7290075Sobrien#include "target.h"
7350397Sobrien
7490075Sobrien/* Provide defaults for stuff that may not be defined when using
7590075Sobrien   sjlj exceptions.  */
7690075Sobrien#ifndef EH_RETURN_STACKADJ_RTX
7790075Sobrien#define EH_RETURN_STACKADJ_RTX 0
7890075Sobrien#endif
7990075Sobrien#ifndef EH_RETURN_HANDLER_RTX
8090075Sobrien#define EH_RETURN_HANDLER_RTX 0
8190075Sobrien#endif
8290075Sobrien#ifndef EH_RETURN_DATA_REGNO
8390075Sobrien#define EH_RETURN_DATA_REGNO(N) INVALID_REGNUM
8490075Sobrien#endif
8550397Sobrien
8650397Sobrien
8790075Sobrien/* Nonzero means enable synchronous exceptions for non-call instructions.  */
8890075Sobrienint flag_non_call_exceptions;
8950397Sobrien
9090075Sobrien/* Protect cleanup actions with must-not-throw regions, with a call
9190075Sobrien   to the given failure handler.  */
9290075Sobrientree (*lang_protect_cleanup_actions) PARAMS ((void));
9350397Sobrien
9490075Sobrien/* Return true if type A catches type B.  */
9590075Sobrienint (*lang_eh_type_covers) PARAMS ((tree a, tree b));
9650397Sobrien
9790075Sobrien/* Map a type to a runtime object to match type.  */
9890075Sobrientree (*lang_eh_runtime_type) PARAMS ((tree));
9950397Sobrien
10096263Sobrien/* A hash table of label to region number.  */
10150397Sobrien
10296263Sobrienstruct ehl_map_entry
10396263Sobrien{
10496263Sobrien  rtx label;
10596263Sobrien  struct eh_region *region;
10696263Sobrien};
10796263Sobrien
10896263Sobrienstatic htab_t exception_handler_label_map;
10996263Sobrien
11090075Sobrienstatic int call_site_base;
11190075Sobrienstatic unsigned int sjlj_funcdef_number;
11290075Sobrienstatic htab_t type_to_runtime_map;
11350397Sobrien
11490075Sobrien/* Describe the SjLj_Function_Context structure.  */
11590075Sobrienstatic tree sjlj_fc_type_node;
11690075Sobrienstatic int sjlj_fc_call_site_ofs;
11790075Sobrienstatic int sjlj_fc_data_ofs;
11890075Sobrienstatic int sjlj_fc_personality_ofs;
11990075Sobrienstatic int sjlj_fc_lsda_ofs;
12090075Sobrienstatic int sjlj_fc_jbuf_ofs;
12190075Sobrien
12290075Sobrien/* Describes one exception region.  */
12390075Sobrienstruct eh_region
12490075Sobrien{
12590075Sobrien  /* The immediately surrounding region.  */
12690075Sobrien  struct eh_region *outer;
12750397Sobrien
12890075Sobrien  /* The list of immediately contained regions.  */
12990075Sobrien  struct eh_region *inner;
13090075Sobrien  struct eh_region *next_peer;
13150397Sobrien
13290075Sobrien  /* An identifier for this region.  */
13390075Sobrien  int region_number;
13450397Sobrien
13596263Sobrien  /* When a region is deleted, its parents inherit the REG_EH_REGION
13696263Sobrien     numbers already assigned.  */
13796263Sobrien  bitmap aka;
13896263Sobrien
13990075Sobrien  /* Each region does exactly one thing.  */
14090075Sobrien  enum eh_region_type
14190075Sobrien  {
14290075Sobrien    ERT_UNKNOWN = 0,
14390075Sobrien    ERT_CLEANUP,
14490075Sobrien    ERT_TRY,
14590075Sobrien    ERT_CATCH,
14690075Sobrien    ERT_ALLOWED_EXCEPTIONS,
14790075Sobrien    ERT_MUST_NOT_THROW,
14890075Sobrien    ERT_THROW,
14990075Sobrien    ERT_FIXUP
15090075Sobrien  } type;
15150397Sobrien
15290075Sobrien  /* Holds the action to perform based on the preceding type.  */
15390075Sobrien  union {
15490075Sobrien    /* A list of catch blocks, a surrounding try block,
15590075Sobrien       and the label for continuing after a catch.  */
15690075Sobrien    struct {
15790075Sobrien      struct eh_region *catch;
15890075Sobrien      struct eh_region *last_catch;
15990075Sobrien      struct eh_region *prev_try;
16090075Sobrien      rtx continue_label;
16190075Sobrien    } try;
16250397Sobrien
16390075Sobrien    /* The list through the catch handlers, the list of type objects
16490075Sobrien       matched, and the list of associated filters.  */
16590075Sobrien    struct {
16690075Sobrien      struct eh_region *next_catch;
16790075Sobrien      struct eh_region *prev_catch;
16890075Sobrien      tree type_list;
16990075Sobrien      tree filter_list;
17090075Sobrien    } catch;
17150397Sobrien
17290075Sobrien    /* A tree_list of allowed types.  */
17390075Sobrien    struct {
17490075Sobrien      tree type_list;
17590075Sobrien      int filter;
17690075Sobrien    } allowed;
17750397Sobrien
17890075Sobrien    /* The type given by a call to "throw foo();", or discovered
17990075Sobrien       for a throw.  */
18090075Sobrien    struct {
18190075Sobrien      tree type;
18290075Sobrien    } throw;
18350397Sobrien
18490075Sobrien    /* Retain the cleanup expression even after expansion so that
18590075Sobrien       we can match up fixup regions.  */
18690075Sobrien    struct {
18790075Sobrien      tree exp;
18890075Sobrien    } cleanup;
18950397Sobrien
19090075Sobrien    /* The real region (by expression and by pointer) that fixup code
19190075Sobrien       should live in.  */
19290075Sobrien    struct {
19390075Sobrien      tree cleanup_exp;
19490075Sobrien      struct eh_region *real_region;
19590075Sobrien    } fixup;
19690075Sobrien  } u;
19750397Sobrien
19890075Sobrien  /* Entry point for this region's handler before landing pads are built.  */
19990075Sobrien  rtx label;
20050397Sobrien
20190075Sobrien  /* Entry point for this region's handler from the runtime eh library.  */
20290075Sobrien  rtx landing_pad;
20350397Sobrien
20490075Sobrien  /* Entry point for this region's handler from an inner region.  */
20590075Sobrien  rtx post_landing_pad;
20650397Sobrien
20790075Sobrien  /* The RESX insn for handing off control to the next outermost handler,
20890075Sobrien     if appropriate.  */
20990075Sobrien  rtx resume;
21090075Sobrien};
21150397Sobrien
21290075Sobrien/* Used to save exception status for each function.  */
21390075Sobrienstruct eh_status
21490075Sobrien{
21590075Sobrien  /* The tree of all regions for this function.  */
21690075Sobrien  struct eh_region *region_tree;
21750397Sobrien
21890075Sobrien  /* The same information as an indexable array.  */
21990075Sobrien  struct eh_region **region_array;
22050397Sobrien
22190075Sobrien  /* The most recently open region.  */
22290075Sobrien  struct eh_region *cur_region;
22350397Sobrien
22490075Sobrien  /* This is the region for which we are processing catch blocks.  */
22590075Sobrien  struct eh_region *try_region;
22650397Sobrien
22790075Sobrien  /* A stack (TREE_LIST) of lists of handlers.  The TREE_VALUE of each
22890075Sobrien     node is itself a TREE_CHAINed list of handlers for regions that
22990075Sobrien     are not yet closed. The TREE_VALUE of each entry contains the
23090075Sobrien     handler for the corresponding entry on the ehstack.  */
23190075Sobrien  tree protect_list;
23250397Sobrien
23390075Sobrien  rtx filter;
23490075Sobrien  rtx exc_ptr;
23550397Sobrien
23690075Sobrien  int built_landing_pads;
23790075Sobrien  int last_region_number;
23850397Sobrien
23990075Sobrien  varray_type ttype_data;
24090075Sobrien  varray_type ehspec_data;
24190075Sobrien  varray_type action_record_data;
24250397Sobrien
24390075Sobrien  struct call_site_record
24490075Sobrien  {
24590075Sobrien    rtx landing_pad;
24690075Sobrien    int action;
24790075Sobrien  } *call_site_data;
24890075Sobrien  int call_site_data_used;
24990075Sobrien  int call_site_data_size;
25050397Sobrien
25190075Sobrien  rtx ehr_stackadj;
25290075Sobrien  rtx ehr_handler;
25390075Sobrien  rtx ehr_label;
25450397Sobrien
25590075Sobrien  rtx sjlj_fc;
25690075Sobrien  rtx sjlj_exit_after;
25790075Sobrien};
25850397Sobrien
25990075Sobrien
26090075Sobrienstatic void mark_eh_region			PARAMS ((struct eh_region *));
26196263Sobrienstatic int mark_ehl_map_entry			PARAMS ((PTR *, PTR));
26296263Sobrienstatic void mark_ehl_map			PARAMS ((void *));
26350397Sobrien
26496263Sobrienstatic void free_region				PARAMS ((struct eh_region *));
26596263Sobrien
26690075Sobrienstatic int t2r_eq				PARAMS ((const PTR,
26790075Sobrien							 const PTR));
26890075Sobrienstatic hashval_t t2r_hash			PARAMS ((const PTR));
26990075Sobrienstatic int t2r_mark_1				PARAMS ((PTR *, PTR));
27090075Sobrienstatic void t2r_mark				PARAMS ((PTR));
27190075Sobrienstatic void add_type_for_runtime		PARAMS ((tree));
27290075Sobrienstatic tree lookup_type_for_runtime		PARAMS ((tree));
27350397Sobrien
27490075Sobrienstatic struct eh_region *expand_eh_region_end	PARAMS ((void));
27550397Sobrien
27690075Sobrienstatic rtx get_exception_filter			PARAMS ((struct function *));
27750397Sobrien
27890075Sobrienstatic void collect_eh_region_array		PARAMS ((void));
27990075Sobrienstatic void resolve_fixup_regions		PARAMS ((void));
28090075Sobrienstatic void remove_fixup_regions		PARAMS ((void));
28190075Sobrienstatic void remove_unreachable_regions		PARAMS ((rtx));
28290075Sobrienstatic void convert_from_eh_region_ranges_1	PARAMS ((rtx *, int *, int));
28350397Sobrien
28490075Sobrienstatic struct eh_region *duplicate_eh_region_1	PARAMS ((struct eh_region *,
28590075Sobrien						     struct inline_remap *));
28690075Sobrienstatic void duplicate_eh_region_2		PARAMS ((struct eh_region *,
28790075Sobrien							 struct eh_region **));
28890075Sobrienstatic int ttypes_filter_eq			PARAMS ((const PTR,
28990075Sobrien							 const PTR));
29090075Sobrienstatic hashval_t ttypes_filter_hash		PARAMS ((const PTR));
29190075Sobrienstatic int ehspec_filter_eq			PARAMS ((const PTR,
29290075Sobrien							 const PTR));
29390075Sobrienstatic hashval_t ehspec_filter_hash		PARAMS ((const PTR));
29490075Sobrienstatic int add_ttypes_entry			PARAMS ((htab_t, tree));
29590075Sobrienstatic int add_ehspec_entry			PARAMS ((htab_t, htab_t,
29690075Sobrien							 tree));
29790075Sobrienstatic void assign_filter_values		PARAMS ((void));
29890075Sobrienstatic void build_post_landing_pads		PARAMS ((void));
29990075Sobrienstatic void connect_post_landing_pads		PARAMS ((void));
30090075Sobrienstatic void dw2_build_landing_pads		PARAMS ((void));
30150397Sobrien
30290075Sobrienstruct sjlj_lp_info;
30390075Sobrienstatic bool sjlj_find_directly_reachable_regions
30490075Sobrien     PARAMS ((struct sjlj_lp_info *));
30590075Sobrienstatic void sjlj_assign_call_site_values
30690075Sobrien     PARAMS ((rtx, struct sjlj_lp_info *));
30790075Sobrienstatic void sjlj_mark_call_sites
30890075Sobrien     PARAMS ((struct sjlj_lp_info *));
30990075Sobrienstatic void sjlj_emit_function_enter		PARAMS ((rtx));
31090075Sobrienstatic void sjlj_emit_function_exit		PARAMS ((void));
31190075Sobrienstatic void sjlj_emit_dispatch_table
31290075Sobrien     PARAMS ((rtx, struct sjlj_lp_info *));
31390075Sobrienstatic void sjlj_build_landing_pads		PARAMS ((void));
31450397Sobrien
31596263Sobrienstatic hashval_t ehl_hash			PARAMS ((const PTR));
31696263Sobrienstatic int ehl_eq				PARAMS ((const PTR,
31796263Sobrien							 const PTR));
31896263Sobrienstatic void ehl_free				PARAMS ((PTR));
31996263Sobrienstatic void add_ehl_entry			PARAMS ((rtx,
32096263Sobrien							 struct eh_region *));
32190075Sobrienstatic void remove_exception_handler_label	PARAMS ((rtx));
32290075Sobrienstatic void remove_eh_handler			PARAMS ((struct eh_region *));
32396263Sobrienstatic int for_each_eh_label_1			PARAMS ((PTR *, PTR));
32450397Sobrien
32590075Sobrienstruct reachable_info;
32650397Sobrien
32790075Sobrien/* The return value of reachable_next_level.  */
32890075Sobrienenum reachable_code
32990075Sobrien{
33090075Sobrien  /* The given exception is not processed by the given region.  */
33190075Sobrien  RNL_NOT_CAUGHT,
33290075Sobrien  /* The given exception may need processing by the given region.  */
33390075Sobrien  RNL_MAYBE_CAUGHT,
33490075Sobrien  /* The given exception is completely processed by the given region.  */
33590075Sobrien  RNL_CAUGHT,
33690075Sobrien  /* The given exception is completely processed by the runtime.  */
33790075Sobrien  RNL_BLOCKED
33890075Sobrien};
33950397Sobrien
34090075Sobrienstatic int check_handled			PARAMS ((tree, tree));
34190075Sobrienstatic void add_reachable_handler
34290075Sobrien     PARAMS ((struct reachable_info *, struct eh_region *,
34390075Sobrien	      struct eh_region *));
34490075Sobrienstatic enum reachable_code reachable_next_level
34590075Sobrien     PARAMS ((struct eh_region *, tree, struct reachable_info *));
34650397Sobrien
34790075Sobrienstatic int action_record_eq			PARAMS ((const PTR,
34890075Sobrien							 const PTR));
34990075Sobrienstatic hashval_t action_record_hash		PARAMS ((const PTR));
35090075Sobrienstatic int add_action_record			PARAMS ((htab_t, int, int));
35190075Sobrienstatic int collect_one_action_chain		PARAMS ((htab_t,
35290075Sobrien							 struct eh_region *));
35390075Sobrienstatic int add_call_site			PARAMS ((rtx, int));
35450397Sobrien
35590075Sobrienstatic void push_uleb128			PARAMS ((varray_type *,
35690075Sobrien							 unsigned int));
35790075Sobrienstatic void push_sleb128			PARAMS ((varray_type *, int));
35890075Sobrien#ifndef HAVE_AS_LEB128
35990075Sobrienstatic int dw2_size_of_call_site_table		PARAMS ((void));
36090075Sobrienstatic int sjlj_size_of_call_site_table		PARAMS ((void));
36190075Sobrien#endif
36290075Sobrienstatic void dw2_output_call_site_table		PARAMS ((void));
36390075Sobrienstatic void sjlj_output_call_site_table		PARAMS ((void));
36450397Sobrien
36590075Sobrien
36690075Sobrien/* Routine to see if exception handling is turned on.
36790075Sobrien   DO_WARN is non-zero if we want to inform the user that exception
36890075Sobrien   handling is turned off.
36950397Sobrien
37090075Sobrien   This is used to ensure that -fexceptions has been specified if the
37190075Sobrien   compiler tries to use any exception-specific functions.  */
37250397Sobrien
37390075Sobrienint
37490075Sobriendoing_eh (do_warn)
37590075Sobrien     int do_warn;
37690075Sobrien{
37790075Sobrien  if (! flag_exceptions)
37890075Sobrien    {
37990075Sobrien      static int warned = 0;
38090075Sobrien      if (! warned && do_warn)
38190075Sobrien	{
38290075Sobrien	  error ("exception handling disabled, use -fexceptions to enable");
38390075Sobrien	  warned = 1;
38490075Sobrien	}
38590075Sobrien      return 0;
38690075Sobrien    }
38790075Sobrien  return 1;
38890075Sobrien}
38950397Sobrien
39090075Sobrien
39190075Sobrienvoid
39290075Sobrieninit_eh ()
39390075Sobrien{
39496263Sobrien  ggc_add_root (&exception_handler_label_map, 1, 1, mark_ehl_map);
39550397Sobrien
39690075Sobrien  if (! flag_exceptions)
39790075Sobrien    return;
39850397Sobrien
39990075Sobrien  type_to_runtime_map = htab_create (31, t2r_hash, t2r_eq, NULL);
40090075Sobrien  ggc_add_root (&type_to_runtime_map, 1, sizeof (htab_t), t2r_mark);
40150397Sobrien
40290075Sobrien  /* Create the SjLj_Function_Context structure.  This should match
40390075Sobrien     the definition in unwind-sjlj.c.  */
40490075Sobrien  if (USING_SJLJ_EXCEPTIONS)
40590075Sobrien    {
40690075Sobrien      tree f_jbuf, f_per, f_lsda, f_prev, f_cs, f_data, tmp;
40750397Sobrien
40890075Sobrien      sjlj_fc_type_node = make_lang_type (RECORD_TYPE);
40990075Sobrien      ggc_add_tree_root (&sjlj_fc_type_node, 1);
41050397Sobrien
41190075Sobrien      f_prev = build_decl (FIELD_DECL, get_identifier ("__prev"),
41290075Sobrien			   build_pointer_type (sjlj_fc_type_node));
41390075Sobrien      DECL_FIELD_CONTEXT (f_prev) = sjlj_fc_type_node;
41450397Sobrien
41590075Sobrien      f_cs = build_decl (FIELD_DECL, get_identifier ("__call_site"),
41690075Sobrien			 integer_type_node);
41790075Sobrien      DECL_FIELD_CONTEXT (f_cs) = sjlj_fc_type_node;
41850397Sobrien
41990075Sobrien      tmp = build_index_type (build_int_2 (4 - 1, 0));
42090075Sobrien      tmp = build_array_type (type_for_mode (word_mode, 1), tmp);
42190075Sobrien      f_data = build_decl (FIELD_DECL, get_identifier ("__data"), tmp);
42290075Sobrien      DECL_FIELD_CONTEXT (f_data) = sjlj_fc_type_node;
42350397Sobrien
42490075Sobrien      f_per = build_decl (FIELD_DECL, get_identifier ("__personality"),
42590075Sobrien			  ptr_type_node);
42690075Sobrien      DECL_FIELD_CONTEXT (f_per) = sjlj_fc_type_node;
42750397Sobrien
42890075Sobrien      f_lsda = build_decl (FIELD_DECL, get_identifier ("__lsda"),
42990075Sobrien			   ptr_type_node);
43090075Sobrien      DECL_FIELD_CONTEXT (f_lsda) = sjlj_fc_type_node;
43150397Sobrien
43290075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP
43390075Sobrien#ifdef JMP_BUF_SIZE
43490075Sobrien      tmp = build_int_2 (JMP_BUF_SIZE - 1, 0);
43590075Sobrien#else
43690075Sobrien      /* Should be large enough for most systems, if it is not,
43790075Sobrien	 JMP_BUF_SIZE should be defined with the proper value.  It will
43890075Sobrien	 also tend to be larger than necessary for most systems, a more
43990075Sobrien	 optimal port will define JMP_BUF_SIZE.  */
44090075Sobrien      tmp = build_int_2 (FIRST_PSEUDO_REGISTER + 2 - 1, 0);
44190075Sobrien#endif
44290075Sobrien#else
44390075Sobrien      /* This is 2 for builtin_setjmp, plus whatever the target requires
44490075Sobrien	 via STACK_SAVEAREA_MODE (SAVE_NONLOCAL).  */
44590075Sobrien      tmp = build_int_2 ((GET_MODE_SIZE (STACK_SAVEAREA_MODE (SAVE_NONLOCAL))
44690075Sobrien			  / GET_MODE_SIZE (Pmode)) + 2 - 1, 0);
44790075Sobrien#endif
44890075Sobrien      tmp = build_index_type (tmp);
44990075Sobrien      tmp = build_array_type (ptr_type_node, tmp);
45090075Sobrien      f_jbuf = build_decl (FIELD_DECL, get_identifier ("__jbuf"), tmp);
45190075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP
45290075Sobrien      /* We don't know what the alignment requirements of the
45390075Sobrien	 runtime's jmp_buf has.  Overestimate.  */
45490075Sobrien      DECL_ALIGN (f_jbuf) = BIGGEST_ALIGNMENT;
45590075Sobrien      DECL_USER_ALIGN (f_jbuf) = 1;
45690075Sobrien#endif
45790075Sobrien      DECL_FIELD_CONTEXT (f_jbuf) = sjlj_fc_type_node;
45850397Sobrien
45990075Sobrien      TYPE_FIELDS (sjlj_fc_type_node) = f_prev;
46090075Sobrien      TREE_CHAIN (f_prev) = f_cs;
46190075Sobrien      TREE_CHAIN (f_cs) = f_data;
46290075Sobrien      TREE_CHAIN (f_data) = f_per;
46390075Sobrien      TREE_CHAIN (f_per) = f_lsda;
46490075Sobrien      TREE_CHAIN (f_lsda) = f_jbuf;
46550397Sobrien
46690075Sobrien      layout_type (sjlj_fc_type_node);
46750397Sobrien
46890075Sobrien      /* Cache the interesting field offsets so that we have
46990075Sobrien	 easy access from rtl.  */
47090075Sobrien      sjlj_fc_call_site_ofs
47190075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_cs), 1)
47290075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_cs), 1) / BITS_PER_UNIT);
47390075Sobrien      sjlj_fc_data_ofs
47490075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_data), 1)
47590075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_data), 1) / BITS_PER_UNIT);
47690075Sobrien      sjlj_fc_personality_ofs
47790075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_per), 1)
47890075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_per), 1) / BITS_PER_UNIT);
47990075Sobrien      sjlj_fc_lsda_ofs
48090075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_lsda), 1)
48190075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_lsda), 1) / BITS_PER_UNIT);
48290075Sobrien      sjlj_fc_jbuf_ofs
48390075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_jbuf), 1)
48490075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_jbuf), 1) / BITS_PER_UNIT);
48590075Sobrien    }
48690075Sobrien}
48750397Sobrien
48890075Sobrienvoid
48990075Sobrieninit_eh_for_function ()
49090075Sobrien{
49190075Sobrien  cfun->eh = (struct eh_status *) xcalloc (1, sizeof (struct eh_status));
49290075Sobrien}
49350397Sobrien
49490075Sobrien/* Mark EH for GC.  */
49550397Sobrien
49690075Sobrienstatic void
49790075Sobrienmark_eh_region (region)
49890075Sobrien     struct eh_region *region;
49990075Sobrien{
50090075Sobrien  if (! region)
50190075Sobrien    return;
50250397Sobrien
50390075Sobrien  switch (region->type)
50490075Sobrien    {
50590075Sobrien    case ERT_UNKNOWN:
50690075Sobrien      /* This can happen if a nested function is inside the body of a region
50790075Sobrien	 and we do a GC as part of processing it.  */
50890075Sobrien      break;
50990075Sobrien    case ERT_CLEANUP:
51090075Sobrien      ggc_mark_tree (region->u.cleanup.exp);
51190075Sobrien      break;
51290075Sobrien    case ERT_TRY:
51390075Sobrien      ggc_mark_rtx (region->u.try.continue_label);
51490075Sobrien      break;
51590075Sobrien    case ERT_CATCH:
51690075Sobrien      ggc_mark_tree (region->u.catch.type_list);
51790075Sobrien      ggc_mark_tree (region->u.catch.filter_list);
51890075Sobrien      break;
51990075Sobrien    case ERT_ALLOWED_EXCEPTIONS:
52090075Sobrien      ggc_mark_tree (region->u.allowed.type_list);
52190075Sobrien      break;
52290075Sobrien    case ERT_MUST_NOT_THROW:
52390075Sobrien      break;
52490075Sobrien    case ERT_THROW:
52590075Sobrien      ggc_mark_tree (region->u.throw.type);
52690075Sobrien      break;
52790075Sobrien    case ERT_FIXUP:
52890075Sobrien      ggc_mark_tree (region->u.fixup.cleanup_exp);
52990075Sobrien      break;
53090075Sobrien    default:
53190075Sobrien      abort ();
53290075Sobrien    }
53350397Sobrien
53490075Sobrien  ggc_mark_rtx (region->label);
53590075Sobrien  ggc_mark_rtx (region->resume);
53690075Sobrien  ggc_mark_rtx (region->landing_pad);
53790075Sobrien  ggc_mark_rtx (region->post_landing_pad);
53890075Sobrien}
53950397Sobrien
54096263Sobrienstatic int
54196263Sobrienmark_ehl_map_entry (pentry, data)
54296263Sobrien     PTR *pentry;
54396263Sobrien     PTR data ATTRIBUTE_UNUSED;
54496263Sobrien{
54596263Sobrien  struct ehl_map_entry *entry = *(struct ehl_map_entry **) pentry;
54696263Sobrien  ggc_mark_rtx (entry->label);
54796263Sobrien  return 1;
54896263Sobrien}
54996263Sobrien
55096263Sobrienstatic void
55196263Sobrienmark_ehl_map (pp)
55296263Sobrien    void *pp;
55396263Sobrien{
55496263Sobrien  htab_t map = *(htab_t *) pp;
55596263Sobrien  if (map)
55696263Sobrien    htab_traverse (map, mark_ehl_map_entry, NULL);
55796263Sobrien}
55896263Sobrien
55990075Sobrienvoid
56090075Sobrienmark_eh_status (eh)
56190075Sobrien     struct eh_status *eh;
56290075Sobrien{
56390075Sobrien  int i;
56450397Sobrien
56590075Sobrien  if (eh == 0)
56690075Sobrien    return;
56750397Sobrien
56890075Sobrien  /* If we've called collect_eh_region_array, use it.  Otherwise walk
56990075Sobrien     the tree non-recursively.  */
57090075Sobrien  if (eh->region_array)
57190075Sobrien    {
57290075Sobrien      for (i = eh->last_region_number; i > 0; --i)
57390075Sobrien	{
57490075Sobrien	  struct eh_region *r = eh->region_array[i];
57590075Sobrien	  if (r && r->region_number == i)
57690075Sobrien	    mark_eh_region (r);
57790075Sobrien	}
57890075Sobrien    }
57990075Sobrien  else if (eh->region_tree)
58090075Sobrien    {
58190075Sobrien      struct eh_region *r = eh->region_tree;
58290075Sobrien      while (1)
58390075Sobrien	{
58490075Sobrien	  mark_eh_region (r);
58590075Sobrien	  if (r->inner)
58690075Sobrien	    r = r->inner;
58790075Sobrien	  else if (r->next_peer)
58890075Sobrien	    r = r->next_peer;
58990075Sobrien	  else
59090075Sobrien	    {
59190075Sobrien	      do {
59290075Sobrien		r = r->outer;
59390075Sobrien		if (r == NULL)
59490075Sobrien		  goto tree_done;
59590075Sobrien	      } while (r->next_peer == NULL);
59690075Sobrien	      r = r->next_peer;
59790075Sobrien	    }
59890075Sobrien	}
59990075Sobrien    tree_done:;
60090075Sobrien    }
60150397Sobrien
60290075Sobrien  ggc_mark_tree (eh->protect_list);
60390075Sobrien  ggc_mark_rtx (eh->filter);
60490075Sobrien  ggc_mark_rtx (eh->exc_ptr);
60590075Sobrien  ggc_mark_tree_varray (eh->ttype_data);
60650397Sobrien
60790075Sobrien  if (eh->call_site_data)
60890075Sobrien    {
60990075Sobrien      for (i = eh->call_site_data_used - 1; i >= 0; --i)
61090075Sobrien	ggc_mark_rtx (eh->call_site_data[i].landing_pad);
61190075Sobrien    }
61250397Sobrien
61390075Sobrien  ggc_mark_rtx (eh->ehr_stackadj);
61490075Sobrien  ggc_mark_rtx (eh->ehr_handler);
61590075Sobrien  ggc_mark_rtx (eh->ehr_label);
61650397Sobrien
61790075Sobrien  ggc_mark_rtx (eh->sjlj_fc);
61890075Sobrien  ggc_mark_rtx (eh->sjlj_exit_after);
61990075Sobrien}
62050397Sobrien
62196263Sobrienstatic inline void
62296263Sobrienfree_region (r)
62396263Sobrien     struct eh_region *r;
62496263Sobrien{
62596263Sobrien  /* Note that the aka bitmap is freed by regset_release_memory.  But if
62696263Sobrien     we ever replace with a non-obstack implementation, this would be
62796263Sobrien     the place to do it.  */
62896263Sobrien  free (r);
62996263Sobrien}
63096263Sobrien
63190075Sobrienvoid
63290075Sobrienfree_eh_status (f)
63390075Sobrien     struct function *f;
63490075Sobrien{
63590075Sobrien  struct eh_status *eh = f->eh;
63650397Sobrien
63790075Sobrien  if (eh->region_array)
63890075Sobrien    {
63990075Sobrien      int i;
64090075Sobrien      for (i = eh->last_region_number; i > 0; --i)
64190075Sobrien	{
64290075Sobrien	  struct eh_region *r = eh->region_array[i];
64390075Sobrien	  /* Mind we don't free a region struct more than once.  */
64490075Sobrien	  if (r && r->region_number == i)
64596263Sobrien	    free_region (r);
64690075Sobrien	}
64790075Sobrien      free (eh->region_array);
64890075Sobrien    }
64990075Sobrien  else if (eh->region_tree)
65090075Sobrien    {
65190075Sobrien      struct eh_region *next, *r = eh->region_tree;
65290075Sobrien      while (1)
65390075Sobrien	{
65490075Sobrien	  if (r->inner)
65590075Sobrien	    r = r->inner;
65690075Sobrien	  else if (r->next_peer)
65790075Sobrien	    {
65890075Sobrien	      next = r->next_peer;
65996263Sobrien	      free_region (r);
66090075Sobrien	      r = next;
66190075Sobrien	    }
66290075Sobrien	  else
66390075Sobrien	    {
66490075Sobrien	      do {
66590075Sobrien	        next = r->outer;
66696263Sobrien	        free_region (r);
66790075Sobrien	        r = next;
66890075Sobrien		if (r == NULL)
66990075Sobrien		  goto tree_done;
67090075Sobrien	      } while (r->next_peer == NULL);
67190075Sobrien	      next = r->next_peer;
67296263Sobrien	      free_region (r);
67390075Sobrien	      r = next;
67490075Sobrien	    }
67590075Sobrien	}
67690075Sobrien    tree_done:;
67790075Sobrien    }
67850397Sobrien
67990075Sobrien  VARRAY_FREE (eh->ttype_data);
68090075Sobrien  VARRAY_FREE (eh->ehspec_data);
68190075Sobrien  VARRAY_FREE (eh->action_record_data);
68290075Sobrien  if (eh->call_site_data)
68390075Sobrien    free (eh->call_site_data);
68450397Sobrien
68590075Sobrien  free (eh);
68690075Sobrien  f->eh = NULL;
68796263Sobrien
68896263Sobrien  if (exception_handler_label_map)
68996263Sobrien    {
69096263Sobrien      htab_delete (exception_handler_label_map);
69196263Sobrien      exception_handler_label_map = NULL;
69296263Sobrien    }
69390075Sobrien}
69450397Sobrien
69590075Sobrien
69690075Sobrien/* Start an exception handling region.  All instructions emitted
69790075Sobrien   after this point are considered to be part of the region until
69890075Sobrien   expand_eh_region_end is invoked.  */
69950397Sobrien
70090075Sobrienvoid
70190075Sobrienexpand_eh_region_start ()
70290075Sobrien{
70390075Sobrien  struct eh_region *new_region;
70490075Sobrien  struct eh_region *cur_region;
70590075Sobrien  rtx note;
70652284Sobrien
70790075Sobrien  if (! doing_eh (0))
70890075Sobrien    return;
70952284Sobrien
71090075Sobrien  /* Insert a new blank region as a leaf in the tree.  */
71190075Sobrien  new_region = (struct eh_region *) xcalloc (1, sizeof (*new_region));
71290075Sobrien  cur_region = cfun->eh->cur_region;
71390075Sobrien  new_region->outer = cur_region;
71490075Sobrien  if (cur_region)
71590075Sobrien    {
71690075Sobrien      new_region->next_peer = cur_region->inner;
71790075Sobrien      cur_region->inner = new_region;
71890075Sobrien    }
71990075Sobrien  else
72090075Sobrien    {
72190075Sobrien      new_region->next_peer = cfun->eh->region_tree;
72290075Sobrien      cfun->eh->region_tree = new_region;
72390075Sobrien    }
72490075Sobrien  cfun->eh->cur_region = new_region;
72552284Sobrien
72690075Sobrien  /* Create a note marking the start of this region.  */
72790075Sobrien  new_region->region_number = ++cfun->eh->last_region_number;
72890075Sobrien  note = emit_note (NULL, NOTE_INSN_EH_REGION_BEG);
72990075Sobrien  NOTE_EH_HANDLER (note) = new_region->region_number;
73090075Sobrien}
73152284Sobrien
73290075Sobrien/* Common code to end a region.  Returns the region just ended.  */
73352284Sobrien
73490075Sobrienstatic struct eh_region *
73590075Sobrienexpand_eh_region_end ()
73690075Sobrien{
73790075Sobrien  struct eh_region *cur_region = cfun->eh->cur_region;
73890075Sobrien  rtx note;
73952284Sobrien
74090075Sobrien  /* Create a note marking the end of this region.  */
74190075Sobrien  note = emit_note (NULL, NOTE_INSN_EH_REGION_END);
74290075Sobrien  NOTE_EH_HANDLER (note) = cur_region->region_number;
74352284Sobrien
74490075Sobrien  /* Pop.  */
74590075Sobrien  cfun->eh->cur_region = cur_region->outer;
74652284Sobrien
74790075Sobrien  return cur_region;
74890075Sobrien}
74950397Sobrien
75090075Sobrien/* End an exception handling region for a cleanup.  HANDLER is an
75190075Sobrien   expression to expand for the cleanup.  */
75250397Sobrien
75390075Sobrienvoid
75490075Sobrienexpand_eh_region_end_cleanup (handler)
75590075Sobrien     tree handler;
75652284Sobrien{
75790075Sobrien  struct eh_region *region;
75890075Sobrien  tree protect_cleanup_actions;
75990075Sobrien  rtx around_label;
76090075Sobrien  rtx data_save[2];
76152284Sobrien
76290075Sobrien  if (! doing_eh (0))
76390075Sobrien    return;
76452284Sobrien
76590075Sobrien  region = expand_eh_region_end ();
76690075Sobrien  region->type = ERT_CLEANUP;
76790075Sobrien  region->label = gen_label_rtx ();
76890075Sobrien  region->u.cleanup.exp = handler;
76952284Sobrien
77090075Sobrien  around_label = gen_label_rtx ();
77190075Sobrien  emit_jump (around_label);
77252284Sobrien
77390075Sobrien  emit_label (region->label);
77450397Sobrien
77590075Sobrien  /* Give the language a chance to specify an action to be taken if an
77690075Sobrien     exception is thrown that would propagate out of the HANDLER.  */
77790075Sobrien  protect_cleanup_actions
77890075Sobrien    = (lang_protect_cleanup_actions
77990075Sobrien       ? (*lang_protect_cleanup_actions) ()
78090075Sobrien       : NULL_TREE);
78150397Sobrien
78290075Sobrien  if (protect_cleanup_actions)
78390075Sobrien    expand_eh_region_start ();
78450397Sobrien
78590075Sobrien  /* In case this cleanup involves an inline destructor with a try block in
78690075Sobrien     it, we need to save the EH return data registers around it.  */
78790075Sobrien  data_save[0] = gen_reg_rtx (Pmode);
78890075Sobrien  emit_move_insn (data_save[0], get_exception_pointer (cfun));
78990075Sobrien  data_save[1] = gen_reg_rtx (word_mode);
79090075Sobrien  emit_move_insn (data_save[1], get_exception_filter (cfun));
79150397Sobrien
79290075Sobrien  expand_expr (handler, const0_rtx, VOIDmode, 0);
79350397Sobrien
79490075Sobrien  emit_move_insn (cfun->eh->exc_ptr, data_save[0]);
79590075Sobrien  emit_move_insn (cfun->eh->filter, data_save[1]);
79650397Sobrien
79790075Sobrien  if (protect_cleanup_actions)
79890075Sobrien    expand_eh_region_end_must_not_throw (protect_cleanup_actions);
79950397Sobrien
80090075Sobrien  /* We need any stack adjustment complete before the around_label.  */
80190075Sobrien  do_pending_stack_adjust ();
80290075Sobrien
80390075Sobrien  /* We delay the generation of the _Unwind_Resume until we generate
80490075Sobrien     landing pads.  We emit a marker here so as to get good control
80590075Sobrien     flow data in the meantime.  */
80690075Sobrien  region->resume
80790075Sobrien    = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
80890075Sobrien  emit_barrier ();
80990075Sobrien
81090075Sobrien  emit_label (around_label);
81150397Sobrien}
81250397Sobrien
81390075Sobrien/* End an exception handling region for a try block, and prepares
81490075Sobrien   for subsequent calls to expand_start_catch.  */
81550397Sobrien
81690075Sobrienvoid
81790075Sobrienexpand_start_all_catch ()
81850397Sobrien{
81990075Sobrien  struct eh_region *region;
82050397Sobrien
82190075Sobrien  if (! doing_eh (1))
82290075Sobrien    return;
82350397Sobrien
82490075Sobrien  region = expand_eh_region_end ();
82590075Sobrien  region->type = ERT_TRY;
82690075Sobrien  region->u.try.prev_try = cfun->eh->try_region;
82790075Sobrien  region->u.try.continue_label = gen_label_rtx ();
82850397Sobrien
82990075Sobrien  cfun->eh->try_region = region;
83090075Sobrien
83190075Sobrien  emit_jump (region->u.try.continue_label);
83250397Sobrien}
83350397Sobrien
83490075Sobrien/* Begin a catch clause.  TYPE is the type caught, a list of such types, or
83590075Sobrien   null if this is a catch-all clause. Providing a type list enables to
83690075Sobrien   associate the catch region with potentially several exception types, which
83790075Sobrien   is useful e.g. for Ada.  */
83850397Sobrien
83990075Sobrienvoid
84090075Sobrienexpand_start_catch (type_or_list)
84190075Sobrien     tree type_or_list;
84250397Sobrien{
84390075Sobrien  struct eh_region *t, *c, *l;
84490075Sobrien  tree type_list;
84550397Sobrien
84690075Sobrien  if (! doing_eh (0))
84790075Sobrien    return;
84890075Sobrien
84990075Sobrien  type_list = type_or_list;
85090075Sobrien
85190075Sobrien  if (type_or_list)
85290075Sobrien    {
85390075Sobrien      /* Ensure to always end up with a type list to normalize further
85490075Sobrien         processing, then register each type against the runtime types
85590075Sobrien         map.  */
85690075Sobrien      tree type_node;
85790075Sobrien
85890075Sobrien      if (TREE_CODE (type_or_list) != TREE_LIST)
85990075Sobrien        type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE);
86090075Sobrien
86190075Sobrien      type_node = type_list;
86290075Sobrien      for (; type_node; type_node = TREE_CHAIN (type_node))
86390075Sobrien        add_type_for_runtime (TREE_VALUE (type_node));
86490075Sobrien    }
86590075Sobrien
86690075Sobrien  expand_eh_region_start ();
86790075Sobrien
86890075Sobrien  t = cfun->eh->try_region;
86990075Sobrien  c = cfun->eh->cur_region;
87090075Sobrien  c->type = ERT_CATCH;
87190075Sobrien  c->u.catch.type_list = type_list;
87290075Sobrien  c->label = gen_label_rtx ();
87390075Sobrien
87490075Sobrien  l = t->u.try.last_catch;
87590075Sobrien  c->u.catch.prev_catch = l;
87690075Sobrien  if (l)
87790075Sobrien    l->u.catch.next_catch = c;
87852284Sobrien  else
87990075Sobrien    t->u.try.catch = c;
88090075Sobrien  t->u.try.last_catch = c;
88150397Sobrien
88290075Sobrien  emit_label (c->label);
88350397Sobrien}
88450397Sobrien
88590075Sobrien/* End a catch clause.  Control will resume after the try/catch block.  */
88690075Sobrien
88790075Sobrienvoid
88890075Sobrienexpand_end_catch ()
88950397Sobrien{
89090075Sobrien  struct eh_region *try_region, *catch_region;
89150397Sobrien
89290075Sobrien  if (! doing_eh (0))
89390075Sobrien    return;
89450397Sobrien
89590075Sobrien  catch_region = expand_eh_region_end ();
89690075Sobrien  try_region = cfun->eh->try_region;
89750397Sobrien
89890075Sobrien  emit_jump (try_region->u.try.continue_label);
89950397Sobrien}
90050397Sobrien
90190075Sobrien/* End a sequence of catch handlers for a try block.  */
90250397Sobrien
90390075Sobrienvoid
90490075Sobrienexpand_end_all_catch ()
90550397Sobrien{
90690075Sobrien  struct eh_region *try_region;
90750397Sobrien
90890075Sobrien  if (! doing_eh (0))
90990075Sobrien    return;
91050397Sobrien
91190075Sobrien  try_region = cfun->eh->try_region;
91290075Sobrien  cfun->eh->try_region = try_region->u.try.prev_try;
91390075Sobrien
91490075Sobrien  emit_label (try_region->u.try.continue_label);
91550397Sobrien}
91650397Sobrien
91790075Sobrien/* End an exception region for an exception type filter.  ALLOWED is a
91890075Sobrien   TREE_LIST of types to be matched by the runtime.  FAILURE is an
91990075Sobrien   expression to invoke if a mismatch occurs.
92050397Sobrien
92190075Sobrien   ??? We could use these semantics for calls to rethrow, too; if we can
92290075Sobrien   see the surrounding catch clause, we know that the exception we're
92390075Sobrien   rethrowing satisfies the "filter" of the catch type.  */
92490075Sobrien
92590075Sobrienvoid
92690075Sobrienexpand_eh_region_end_allowed (allowed, failure)
92790075Sobrien     tree allowed, failure;
92850397Sobrien{
92990075Sobrien  struct eh_region *region;
93090075Sobrien  rtx around_label;
93150397Sobrien
93290075Sobrien  if (! doing_eh (0))
93390075Sobrien    return;
93450397Sobrien
93590075Sobrien  region = expand_eh_region_end ();
93690075Sobrien  region->type = ERT_ALLOWED_EXCEPTIONS;
93790075Sobrien  region->u.allowed.type_list = allowed;
93890075Sobrien  region->label = gen_label_rtx ();
93950397Sobrien
94090075Sobrien  for (; allowed ; allowed = TREE_CHAIN (allowed))
94190075Sobrien    add_type_for_runtime (TREE_VALUE (allowed));
94250397Sobrien
94390075Sobrien  /* We must emit the call to FAILURE here, so that if this function
94490075Sobrien     throws a different exception, that it will be processed by the
94590075Sobrien     correct region.  */
94690075Sobrien
94790075Sobrien  around_label = gen_label_rtx ();
94890075Sobrien  emit_jump (around_label);
94990075Sobrien
95090075Sobrien  emit_label (region->label);
95190075Sobrien  expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL);
95290075Sobrien  /* We must adjust the stack before we reach the AROUND_LABEL because
95390075Sobrien     the call to FAILURE does not occur on all paths to the
95490075Sobrien     AROUND_LABEL.  */
95590075Sobrien  do_pending_stack_adjust ();
95690075Sobrien
95790075Sobrien  emit_label (around_label);
95850397Sobrien}
95950397Sobrien
96090075Sobrien/* End an exception region for a must-not-throw filter.  FAILURE is an
96190075Sobrien   expression invoke if an uncaught exception propagates this far.
96290075Sobrien
96390075Sobrien   This is conceptually identical to expand_eh_region_end_allowed with
96490075Sobrien   an empty allowed list (if you passed "std::terminate" instead of
96590075Sobrien   "__cxa_call_unexpected"), but they are represented differently in
96690075Sobrien   the C++ LSDA.  */
96790075Sobrien
96890075Sobrienvoid
96990075Sobrienexpand_eh_region_end_must_not_throw (failure)
97090075Sobrien     tree failure;
97150397Sobrien{
97290075Sobrien  struct eh_region *region;
97390075Sobrien  rtx around_label;
97474722Sobrien
97590075Sobrien  if (! doing_eh (0))
97690075Sobrien    return;
97774722Sobrien
97890075Sobrien  region = expand_eh_region_end ();
97990075Sobrien  region->type = ERT_MUST_NOT_THROW;
98090075Sobrien  region->label = gen_label_rtx ();
98174722Sobrien
98290075Sobrien  /* We must emit the call to FAILURE here, so that if this function
98390075Sobrien     throws a different exception, that it will be processed by the
98490075Sobrien     correct region.  */
98590075Sobrien
98690075Sobrien  around_label = gen_label_rtx ();
98790075Sobrien  emit_jump (around_label);
98890075Sobrien
98990075Sobrien  emit_label (region->label);
99090075Sobrien  expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL);
99190075Sobrien
99290075Sobrien  emit_label (around_label);
99350397Sobrien}
99450397Sobrien
99590075Sobrien/* End an exception region for a throw.  No handling goes on here,
99690075Sobrien   but it's the easiest way for the front-end to indicate what type
99790075Sobrien   is being thrown.  */
99890075Sobrien
99990075Sobrienvoid
100090075Sobrienexpand_eh_region_end_throw (type)
100190075Sobrien     tree type;
100250397Sobrien{
100390075Sobrien  struct eh_region *region;
100450397Sobrien
100590075Sobrien  if (! doing_eh (0))
100690075Sobrien    return;
100750397Sobrien
100890075Sobrien  region = expand_eh_region_end ();
100990075Sobrien  region->type = ERT_THROW;
101090075Sobrien  region->u.throw.type = type;
101190075Sobrien}
101250397Sobrien
101390075Sobrien/* End a fixup region.  Within this region the cleanups for the immediately
101490075Sobrien   enclosing region are _not_ run.  This is used for goto cleanup to avoid
101590075Sobrien   destroying an object twice.
101650397Sobrien
101790075Sobrien   This would be an extraordinarily simple prospect, were it not for the
101890075Sobrien   fact that we don't actually know what the immediately enclosing region
101990075Sobrien   is.  This surprising fact is because expand_cleanups is currently
102090075Sobrien   generating a sequence that it will insert somewhere else.  We collect
102190075Sobrien   the proper notion of "enclosing" in convert_from_eh_region_ranges.  */
102250397Sobrien
102390075Sobrienvoid
102490075Sobrienexpand_eh_region_end_fixup (handler)
102590075Sobrien     tree handler;
102650397Sobrien{
102790075Sobrien  struct eh_region *fixup;
102850397Sobrien
102990075Sobrien  if (! doing_eh (0))
103090075Sobrien    return;
103190075Sobrien
103290075Sobrien  fixup = expand_eh_region_end ();
103390075Sobrien  fixup->type = ERT_FIXUP;
103490075Sobrien  fixup->u.fixup.cleanup_exp = handler;
103550397Sobrien}
103650397Sobrien
103790075Sobrien/* Return an rtl expression for a pointer to the exception object
103890075Sobrien   within a handler.  */
103950397Sobrien
104090075Sobrienrtx
104190075Sobrienget_exception_pointer (fun)
104290075Sobrien     struct function *fun;
104350397Sobrien{
104490075Sobrien  rtx exc_ptr = fun->eh->exc_ptr;
104590075Sobrien  if (fun == cfun && ! exc_ptr)
104650397Sobrien    {
104790075Sobrien      exc_ptr = gen_reg_rtx (Pmode);
104890075Sobrien      fun->eh->exc_ptr = exc_ptr;
104950397Sobrien    }
105090075Sobrien  return exc_ptr;
105150397Sobrien}
105250397Sobrien
105390075Sobrien/* Return an rtl expression for the exception dispatch filter
105490075Sobrien   within a handler.  */
105550397Sobrien
105690075Sobrienstatic rtx
105790075Sobrienget_exception_filter (fun)
105890075Sobrien     struct function *fun;
105950397Sobrien{
106090075Sobrien  rtx filter = fun->eh->filter;
106190075Sobrien  if (fun == cfun && ! filter)
106250397Sobrien    {
106390075Sobrien      filter = gen_reg_rtx (word_mode);
106490075Sobrien      fun->eh->filter = filter;
106550397Sobrien    }
106690075Sobrien  return filter;
106750397Sobrien}
106890075Sobrien
106990075Sobrien/* Begin a region that will contain entries created with
107090075Sobrien   add_partial_entry.  */
107150397Sobrien
107290075Sobrienvoid
107390075Sobrienbegin_protect_partials ()
107450397Sobrien{
107590075Sobrien  /* Push room for a new list.  */
107690075Sobrien  cfun->eh->protect_list
107790075Sobrien    = tree_cons (NULL_TREE, NULL_TREE, cfun->eh->protect_list);
107890075Sobrien}
107950397Sobrien
108090075Sobrien/* Start a new exception region for a region of code that has a
108190075Sobrien   cleanup action and push the HANDLER for the region onto
108290075Sobrien   protect_list. All of the regions created with add_partial_entry
108390075Sobrien   will be ended when end_protect_partials is invoked.
108450397Sobrien
108590075Sobrien   ??? The only difference between this purpose and that of
108690075Sobrien   expand_decl_cleanup is that in this case, we only want the cleanup to
108790075Sobrien   run if an exception is thrown.  This should also be handled using
108890075Sobrien   binding levels.  */
108950397Sobrien
109090075Sobrienvoid
109190075Sobrienadd_partial_entry (handler)
109290075Sobrien     tree handler;
109390075Sobrien{
109490075Sobrien  expand_eh_region_start ();
109550397Sobrien
109690075Sobrien  /* Add this entry to the front of the list.  */
109790075Sobrien  TREE_VALUE (cfun->eh->protect_list)
109890075Sobrien    = tree_cons (NULL_TREE, handler, TREE_VALUE (cfun->eh->protect_list));
109990075Sobrien}
110050397Sobrien
110190075Sobrien/* End all the pending exception regions on protect_list.  */
110250397Sobrien
110390075Sobrienvoid
110490075Sobrienend_protect_partials ()
110590075Sobrien{
110690075Sobrien  tree t;
110750397Sobrien
110890075Sobrien  /* Pop the topmost entry.  */
110990075Sobrien  t = TREE_VALUE (cfun->eh->protect_list);
111090075Sobrien  cfun->eh->protect_list = TREE_CHAIN (cfun->eh->protect_list);
111190075Sobrien
111290075Sobrien  /* End all the exception regions.  */
111390075Sobrien  for (; t; t = TREE_CHAIN (t))
111490075Sobrien    expand_eh_region_end_cleanup (TREE_VALUE (t));
111550397Sobrien}
111650397Sobrien
111790075Sobrien
111890075Sobrien/* This section is for the exception handling specific optimization pass.  */
111950397Sobrien
112090075Sobrien/* Random access the exception region tree.  It's just as simple to
112190075Sobrien   collect the regions this way as in expand_eh_region_start, but
112290075Sobrien   without having to realloc memory.  */
112390075Sobrien
112490075Sobrienstatic void
112590075Sobriencollect_eh_region_array ()
112650397Sobrien{
112790075Sobrien  struct eh_region **array, *i;
112850397Sobrien
112990075Sobrien  i = cfun->eh->region_tree;
113090075Sobrien  if (! i)
113190075Sobrien    return;
113250397Sobrien
113390075Sobrien  array = xcalloc (cfun->eh->last_region_number + 1, sizeof (*array));
113490075Sobrien  cfun->eh->region_array = array;
113550397Sobrien
113690075Sobrien  while (1)
113790075Sobrien    {
113890075Sobrien      array[i->region_number] = i;
113950397Sobrien
114090075Sobrien      /* If there are sub-regions, process them.  */
114190075Sobrien      if (i->inner)
114290075Sobrien	i = i->inner;
114390075Sobrien      /* If there are peers, process them.  */
114490075Sobrien      else if (i->next_peer)
114590075Sobrien	i = i->next_peer;
114690075Sobrien      /* Otherwise, step back up the tree to the next peer.  */
114790075Sobrien      else
114890075Sobrien	{
114990075Sobrien	  do {
115090075Sobrien	    i = i->outer;
115190075Sobrien	    if (i == NULL)
115290075Sobrien	      return;
115390075Sobrien	  } while (i->next_peer == NULL);
115490075Sobrien	  i = i->next_peer;
115590075Sobrien	}
115690075Sobrien    }
115790075Sobrien}
115850397Sobrien
115990075Sobrienstatic void
116090075Sobrienresolve_fixup_regions ()
116150397Sobrien{
116290075Sobrien  int i, j, n = cfun->eh->last_region_number;
116350397Sobrien
116490075Sobrien  for (i = 1; i <= n; ++i)
116590075Sobrien    {
116690075Sobrien      struct eh_region *fixup = cfun->eh->region_array[i];
116790075Sobrien      struct eh_region *cleanup = 0;
116850397Sobrien
116990075Sobrien      if (! fixup || fixup->type != ERT_FIXUP)
117090075Sobrien	continue;
117150397Sobrien
117290075Sobrien      for (j = 1; j <= n; ++j)
117390075Sobrien	{
117490075Sobrien	  cleanup = cfun->eh->region_array[j];
117590075Sobrien	  if (cleanup->type == ERT_CLEANUP
117690075Sobrien	      && cleanup->u.cleanup.exp == fixup->u.fixup.cleanup_exp)
117790075Sobrien	    break;
117890075Sobrien	}
117990075Sobrien      if (j > n)
118090075Sobrien	abort ();
118190075Sobrien
118290075Sobrien      fixup->u.fixup.real_region = cleanup->outer;
118390075Sobrien    }
118450397Sobrien}
118550397Sobrien
118690075Sobrien/* Now that we've discovered what region actually encloses a fixup,
118790075Sobrien   we can shuffle pointers and remove them from the tree.  */
118850397Sobrien
118950397Sobrienstatic void
119090075Sobrienremove_fixup_regions ()
119150397Sobrien{
119290075Sobrien  int i;
119390075Sobrien  rtx insn, note;
119490075Sobrien  struct eh_region *fixup;
119590075Sobrien
119690075Sobrien  /* Walk the insn chain and adjust the REG_EH_REGION numbers
119790075Sobrien     for instructions referencing fixup regions.  This is only
119890075Sobrien     strictly necessary for fixup regions with no parent, but
119990075Sobrien     doesn't hurt to do it for all regions.  */
120090075Sobrien  for (insn = get_insns(); insn ; insn = NEXT_INSN (insn))
120190075Sobrien    if (INSN_P (insn)
120290075Sobrien	&& (note = find_reg_note (insn, REG_EH_REGION, NULL))
120390075Sobrien	&& INTVAL (XEXP (note, 0)) > 0
120490075Sobrien	&& (fixup = cfun->eh->region_array[INTVAL (XEXP (note, 0))])
120590075Sobrien	&& fixup->type == ERT_FIXUP)
120650397Sobrien      {
120790075Sobrien	if (fixup->u.fixup.real_region)
120890075Sobrien	  XEXP (note, 0) = GEN_INT (fixup->u.fixup.real_region->region_number);
120990075Sobrien	else
121090075Sobrien	  remove_note (insn, note);
121150397Sobrien      }
121250397Sobrien
121390075Sobrien  /* Remove the fixup regions from the tree.  */
121490075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
121590075Sobrien    {
121690075Sobrien      fixup = cfun->eh->region_array[i];
121790075Sobrien      if (! fixup)
121890075Sobrien	continue;
121950397Sobrien
122090075Sobrien      /* Allow GC to maybe free some memory.  */
122190075Sobrien      if (fixup->type == ERT_CLEANUP)
122290075Sobrien        fixup->u.cleanup.exp = NULL_TREE;
122350397Sobrien
122490075Sobrien      if (fixup->type != ERT_FIXUP)
122590075Sobrien	continue;
122650397Sobrien
122790075Sobrien      if (fixup->inner)
122890075Sobrien	{
122990075Sobrien	  struct eh_region *parent, *p, **pp;
123050397Sobrien
123190075Sobrien	  parent = fixup->u.fixup.real_region;
123252284Sobrien
123390075Sobrien	  /* Fix up the children's parent pointers; find the end of
123490075Sobrien	     the list.  */
123590075Sobrien	  for (p = fixup->inner; ; p = p->next_peer)
123690075Sobrien	    {
123790075Sobrien	      p->outer = parent;
123890075Sobrien	      if (! p->next_peer)
123990075Sobrien		break;
124090075Sobrien	    }
124150397Sobrien
124290075Sobrien	  /* In the tree of cleanups, only outer-inner ordering matters.
124390075Sobrien	     So link the children back in anywhere at the correct level.  */
124490075Sobrien	  if (parent)
124590075Sobrien	    pp = &parent->inner;
124690075Sobrien	  else
124790075Sobrien	    pp = &cfun->eh->region_tree;
124890075Sobrien	  p->next_peer = *pp;
124990075Sobrien	  *pp = fixup->inner;
125090075Sobrien	  fixup->inner = NULL;
125190075Sobrien	}
125290075Sobrien
125390075Sobrien      remove_eh_handler (fixup);
125450397Sobrien    }
125550397Sobrien}
125650397Sobrien
125790075Sobrien/* Remove all regions whose labels are not reachable from insns.  */
125852284Sobrien
125990075Sobrienstatic void
126090075Sobrienremove_unreachable_regions (insns)
126190075Sobrien     rtx insns;
126252284Sobrien{
126390075Sobrien  int i, *uid_region_num;
126490075Sobrien  bool *reachable;
126590075Sobrien  struct eh_region *r;
126690075Sobrien  rtx insn;
126752284Sobrien
126890075Sobrien  uid_region_num = xcalloc (get_max_uid (), sizeof(int));
126990075Sobrien  reachable = xcalloc (cfun->eh->last_region_number + 1, sizeof(bool));
127052284Sobrien
127190075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
127290075Sobrien    {
127390075Sobrien      r = cfun->eh->region_array[i];
127490075Sobrien      if (!r || r->region_number != i)
127590075Sobrien	continue;
127652284Sobrien
127790075Sobrien      if (r->resume)
127890075Sobrien        {
127990075Sobrien	  if (uid_region_num[INSN_UID (r->resume)])
128090075Sobrien	    abort ();
128190075Sobrien	  uid_region_num[INSN_UID (r->resume)] = i;
128290075Sobrien        }
128390075Sobrien      if (r->label)
128490075Sobrien        {
128590075Sobrien	  if (uid_region_num[INSN_UID (r->label)])
128690075Sobrien	    abort ();
128790075Sobrien	  uid_region_num[INSN_UID (r->label)] = i;
128890075Sobrien        }
128990075Sobrien      if (r->type == ERT_TRY && r->u.try.continue_label)
129090075Sobrien        {
129190075Sobrien	  if (uid_region_num[INSN_UID (r->u.try.continue_label)])
129290075Sobrien	    abort ();
129390075Sobrien	  uid_region_num[INSN_UID (r->u.try.continue_label)] = i;
129490075Sobrien        }
129552284Sobrien    }
129652284Sobrien
129790075Sobrien  for (insn = insns; insn; insn = NEXT_INSN (insn))
129890075Sobrien    reachable[uid_region_num[INSN_UID (insn)]] = true;
129950397Sobrien
130090075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
130150397Sobrien    {
130290075Sobrien      r = cfun->eh->region_array[i];
130390075Sobrien      if (r && r->region_number == i && !reachable[i])
130450397Sobrien	{
130590075Sobrien	  /* Don't remove ERT_THROW regions if their outer region
130690075Sobrien	     is reachable.  */
130790075Sobrien	  if (r->type == ERT_THROW
130890075Sobrien	      && r->outer
130990075Sobrien	      && reachable[r->outer->region_number])
131090075Sobrien	    continue;
131190075Sobrien
131290075Sobrien	  remove_eh_handler (r);
131350397Sobrien	}
131450397Sobrien    }
131590075Sobrien
131690075Sobrien  free (reachable);
131790075Sobrien  free (uid_region_num);
131850397Sobrien}
131950397Sobrien
132090075Sobrien/* Turn NOTE_INSN_EH_REGION notes into REG_EH_REGION notes for each
132190075Sobrien   can_throw instruction in the region.  */
132250397Sobrien
132390075Sobrienstatic void
132490075Sobrienconvert_from_eh_region_ranges_1 (pinsns, orig_sp, cur)
132590075Sobrien     rtx *pinsns;
132690075Sobrien     int *orig_sp;
132790075Sobrien     int cur;
132850397Sobrien{
132990075Sobrien  int *sp = orig_sp;
133090075Sobrien  rtx insn, next;
133150397Sobrien
133290075Sobrien  for (insn = *pinsns; insn ; insn = next)
133390075Sobrien    {
133490075Sobrien      next = NEXT_INSN (insn);
133590075Sobrien      if (GET_CODE (insn) == NOTE)
133690075Sobrien	{
133790075Sobrien	  int kind = NOTE_LINE_NUMBER (insn);
133890075Sobrien	  if (kind == NOTE_INSN_EH_REGION_BEG
133990075Sobrien	      || kind == NOTE_INSN_EH_REGION_END)
134090075Sobrien	    {
134190075Sobrien	      if (kind == NOTE_INSN_EH_REGION_BEG)
134290075Sobrien		{
134390075Sobrien		  struct eh_region *r;
134450397Sobrien
134590075Sobrien		  *sp++ = cur;
134690075Sobrien		  cur = NOTE_EH_HANDLER (insn);
134750397Sobrien
134890075Sobrien		  r = cfun->eh->region_array[cur];
134990075Sobrien		  if (r->type == ERT_FIXUP)
135090075Sobrien		    {
135190075Sobrien		      r = r->u.fixup.real_region;
135290075Sobrien		      cur = r ? r->region_number : 0;
135390075Sobrien		    }
135490075Sobrien		  else if (r->type == ERT_CATCH)
135590075Sobrien		    {
135690075Sobrien		      r = r->outer;
135790075Sobrien		      cur = r ? r->region_number : 0;
135890075Sobrien		    }
135990075Sobrien		}
136090075Sobrien	      else
136190075Sobrien		cur = *--sp;
136250397Sobrien
136390075Sobrien	      /* Removing the first insn of a CALL_PLACEHOLDER sequence
136490075Sobrien		 requires extra care to adjust sequence start.  */
136590075Sobrien	      if (insn == *pinsns)
136690075Sobrien		*pinsns = next;
136790075Sobrien	      remove_insn (insn);
136890075Sobrien	      continue;
136990075Sobrien	    }
137090075Sobrien	}
137190075Sobrien      else if (INSN_P (insn))
137290075Sobrien	{
137390075Sobrien	  if (cur > 0
137490075Sobrien	      && ! find_reg_note (insn, REG_EH_REGION, NULL_RTX)
137590075Sobrien	      /* Calls can always potentially throw exceptions, unless
137690075Sobrien		 they have a REG_EH_REGION note with a value of 0 or less.
137790075Sobrien		 Which should be the only possible kind so far.  */
137890075Sobrien	      && (GET_CODE (insn) == CALL_INSN
137990075Sobrien		  /* If we wanted exceptions for non-call insns, then
138090075Sobrien		     any may_trap_p instruction could throw.  */
138190075Sobrien		  || (flag_non_call_exceptions
138290075Sobrien		      && GET_CODE (PATTERN (insn)) != CLOBBER
138390075Sobrien		      && GET_CODE (PATTERN (insn)) != USE
138490075Sobrien		      && may_trap_p (PATTERN (insn)))))
138590075Sobrien	    {
138690075Sobrien	      REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION, GEN_INT (cur),
138790075Sobrien						  REG_NOTES (insn));
138890075Sobrien	    }
138950397Sobrien
139090075Sobrien	  if (GET_CODE (insn) == CALL_INSN
139190075Sobrien	      && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
139290075Sobrien	    {
139390075Sobrien	      convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 0),
139490075Sobrien					       sp, cur);
139590075Sobrien	      convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 1),
139690075Sobrien					       sp, cur);
139790075Sobrien	      convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 2),
139890075Sobrien					       sp, cur);
139990075Sobrien	    }
140090075Sobrien	}
140190075Sobrien    }
140250397Sobrien
140390075Sobrien  if (sp != orig_sp)
140490075Sobrien    abort ();
140550397Sobrien}
140650397Sobrien
140790075Sobrienvoid
140890075Sobrienconvert_from_eh_region_ranges ()
140950397Sobrien{
141090075Sobrien  int *stack;
141190075Sobrien  rtx insns;
141250397Sobrien
141390075Sobrien  collect_eh_region_array ();
141490075Sobrien  resolve_fixup_regions ();
141550397Sobrien
141690075Sobrien  stack = xmalloc (sizeof (int) * (cfun->eh->last_region_number + 1));
141790075Sobrien  insns = get_insns ();
141890075Sobrien  convert_from_eh_region_ranges_1 (&insns, stack, 0);
141990075Sobrien  free (stack);
142050397Sobrien
142190075Sobrien  remove_fixup_regions ();
142290075Sobrien  remove_unreachable_regions (insns);
142350397Sobrien}
142450397Sobrien
142596263Sobrienstatic void
142696263Sobrienadd_ehl_entry (label, region)
142796263Sobrien     rtx label;
142896263Sobrien     struct eh_region *region;
142996263Sobrien{
143096263Sobrien  struct ehl_map_entry **slot, *entry;
143196263Sobrien
143296263Sobrien  LABEL_PRESERVE_P (label) = 1;
143396263Sobrien
143496263Sobrien  entry = (struct ehl_map_entry *) xmalloc (sizeof (*entry));
143596263Sobrien  entry->label = label;
143696263Sobrien  entry->region = region;
143796263Sobrien
143896263Sobrien  slot = (struct ehl_map_entry **)
143996263Sobrien    htab_find_slot (exception_handler_label_map, entry, INSERT);
144096263Sobrien
144196263Sobrien  /* Before landing pad creation, each exception handler has its own
144296263Sobrien     label.  After landing pad creation, the exception handlers may
144396263Sobrien     share landing pads.  This is ok, since maybe_remove_eh_handler
144496263Sobrien     only requires the 1-1 mapping before landing pad creation.  */
144596263Sobrien  if (*slot && !cfun->eh->built_landing_pads)
144696263Sobrien    abort ();
144796263Sobrien
144896263Sobrien  *slot = entry;
144996263Sobrien}
145096263Sobrien
145196263Sobrienstatic void
145296263Sobrienehl_free (pentry)
145396263Sobrien     PTR pentry;
145496263Sobrien{
145596263Sobrien  struct ehl_map_entry *entry = (struct ehl_map_entry *)pentry;
145696263Sobrien  LABEL_PRESERVE_P (entry->label) = 0;
145796263Sobrien  free (entry);
145896263Sobrien}
145996263Sobrien
146090075Sobrienvoid
146190075Sobrienfind_exception_handler_labels ()
146290075Sobrien{
146390075Sobrien  int i;
146450397Sobrien
146596263Sobrien  if (exception_handler_label_map)
146696263Sobrien    htab_empty (exception_handler_label_map);
146796263Sobrien  else
146896263Sobrien    {
146996263Sobrien      /* ??? The expansion factor here (3/2) must be greater than the htab
147096263Sobrien	 occupancy factor (4/3) to avoid unnecessary resizing.  */
147196263Sobrien      exception_handler_label_map
147296263Sobrien        = htab_create (cfun->eh->last_region_number * 3 / 2,
147396263Sobrien		       ehl_hash, ehl_eq, ehl_free);
147496263Sobrien    }
147550397Sobrien
147690075Sobrien  if (cfun->eh->region_tree == NULL)
147790075Sobrien    return;
147890075Sobrien
147990075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
148050397Sobrien    {
148190075Sobrien      struct eh_region *region = cfun->eh->region_array[i];
148290075Sobrien      rtx lab;
148350397Sobrien
148490075Sobrien      if (! region || region->region_number != i)
148590075Sobrien	continue;
148690075Sobrien      if (cfun->eh->built_landing_pads)
148790075Sobrien	lab = region->landing_pad;
148890075Sobrien      else
148990075Sobrien	lab = region->label;
149050397Sobrien
149190075Sobrien      if (lab)
149296263Sobrien	add_ehl_entry (lab, region);
149350397Sobrien    }
149490075Sobrien
149590075Sobrien  /* For sjlj exceptions, need the return label to remain live until
149690075Sobrien     after landing pad generation.  */
149790075Sobrien  if (USING_SJLJ_EXCEPTIONS && ! cfun->eh->built_landing_pads)
149896263Sobrien    add_ehl_entry (return_label, NULL);
149996263Sobrien}
150090075Sobrien
150196263Sobrienbool
150296263Sobriencurrent_function_has_exception_handlers ()
150396263Sobrien{
150496263Sobrien  int i;
150596263Sobrien
150696263Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
150796263Sobrien    {
150896263Sobrien      struct eh_region *region = cfun->eh->region_array[i];
150996263Sobrien
151096263Sobrien      if (! region || region->region_number != i)
151196263Sobrien	continue;
151296263Sobrien      if (region->type != ERT_THROW)
151396263Sobrien	return true;
151496263Sobrien    }
151596263Sobrien
151696263Sobrien  return false;
151750397Sobrien}
151890075Sobrien
151990075Sobrienstatic struct eh_region *
152090075Sobrienduplicate_eh_region_1 (o, map)
152190075Sobrien     struct eh_region *o;
152290075Sobrien     struct inline_remap *map;
152350397Sobrien{
152490075Sobrien  struct eh_region *n
152590075Sobrien    = (struct eh_region *) xcalloc (1, sizeof (struct eh_region));
152650397Sobrien
152790075Sobrien  n->region_number = o->region_number + cfun->eh->last_region_number;
152890075Sobrien  n->type = o->type;
152950397Sobrien
153090075Sobrien  switch (n->type)
153190075Sobrien    {
153290075Sobrien    case ERT_CLEANUP:
153390075Sobrien    case ERT_MUST_NOT_THROW:
153490075Sobrien      break;
153550397Sobrien
153690075Sobrien    case ERT_TRY:
153790075Sobrien      if (o->u.try.continue_label)
153890075Sobrien	n->u.try.continue_label
153990075Sobrien	  = get_label_from_map (map,
154090075Sobrien				CODE_LABEL_NUMBER (o->u.try.continue_label));
154190075Sobrien      break;
154250397Sobrien
154390075Sobrien    case ERT_CATCH:
154490075Sobrien      n->u.catch.type_list = o->u.catch.type_list;
154590075Sobrien      break;
154650397Sobrien
154790075Sobrien    case ERT_ALLOWED_EXCEPTIONS:
154890075Sobrien      n->u.allowed.type_list = o->u.allowed.type_list;
154990075Sobrien      break;
155050397Sobrien
155190075Sobrien    case ERT_THROW:
155290075Sobrien      n->u.throw.type = o->u.throw.type;
155350397Sobrien
155490075Sobrien    default:
155590075Sobrien      abort ();
155690075Sobrien    }
155750397Sobrien
155890075Sobrien  if (o->label)
155990075Sobrien    n->label = get_label_from_map (map, CODE_LABEL_NUMBER (o->label));
156090075Sobrien  if (o->resume)
156190075Sobrien    {
156290075Sobrien      n->resume = map->insn_map[INSN_UID (o->resume)];
156390075Sobrien      if (n->resume == NULL)
156490075Sobrien	abort ();
156590075Sobrien    }
156650397Sobrien
156790075Sobrien  return n;
156850397Sobrien}
156950397Sobrien
157050397Sobrienstatic void
157190075Sobrienduplicate_eh_region_2 (o, n_array)
157290075Sobrien     struct eh_region *o;
157390075Sobrien     struct eh_region **n_array;
157450397Sobrien{
157590075Sobrien  struct eh_region *n = n_array[o->region_number];
157650397Sobrien
157790075Sobrien  switch (n->type)
157890075Sobrien    {
157990075Sobrien    case ERT_TRY:
158090075Sobrien      n->u.try.catch = n_array[o->u.try.catch->region_number];
158190075Sobrien      n->u.try.last_catch = n_array[o->u.try.last_catch->region_number];
158290075Sobrien      break;
158350397Sobrien
158490075Sobrien    case ERT_CATCH:
158590075Sobrien      if (o->u.catch.next_catch)
158690075Sobrien        n->u.catch.next_catch = n_array[o->u.catch.next_catch->region_number];
158790075Sobrien      if (o->u.catch.prev_catch)
158890075Sobrien        n->u.catch.prev_catch = n_array[o->u.catch.prev_catch->region_number];
158990075Sobrien      break;
159050397Sobrien
159190075Sobrien    default:
159290075Sobrien      break;
159390075Sobrien    }
159490075Sobrien
159590075Sobrien  if (o->outer)
159690075Sobrien    n->outer = n_array[o->outer->region_number];
159790075Sobrien  if (o->inner)
159890075Sobrien    n->inner = n_array[o->inner->region_number];
159990075Sobrien  if (o->next_peer)
160090075Sobrien    n->next_peer = n_array[o->next_peer->region_number];
160190075Sobrien}
160290075Sobrien
160390075Sobrienint
160490075Sobrienduplicate_eh_regions (ifun, map)
160590075Sobrien     struct function *ifun;
160690075Sobrien     struct inline_remap *map;
160750397Sobrien{
160890075Sobrien  int ifun_last_region_number = ifun->eh->last_region_number;
160990075Sobrien  struct eh_region **n_array, *root, *cur;
161090075Sobrien  int i;
161150397Sobrien
161290075Sobrien  if (ifun_last_region_number == 0)
161390075Sobrien    return 0;
161450397Sobrien
161590075Sobrien  n_array = xcalloc (ifun_last_region_number + 1, sizeof (*n_array));
161650397Sobrien
161790075Sobrien  for (i = 1; i <= ifun_last_region_number; ++i)
161890075Sobrien    {
161990075Sobrien      cur = ifun->eh->region_array[i];
162090075Sobrien      if (!cur || cur->region_number != i)
162190075Sobrien	continue;
162290075Sobrien      n_array[i] = duplicate_eh_region_1 (cur, map);
162390075Sobrien    }
162490075Sobrien  for (i = 1; i <= ifun_last_region_number; ++i)
162590075Sobrien    {
162690075Sobrien      cur = ifun->eh->region_array[i];
162790075Sobrien      if (!cur || cur->region_number != i)
162890075Sobrien	continue;
162990075Sobrien      duplicate_eh_region_2 (cur, n_array);
163090075Sobrien    }
163150397Sobrien
163290075Sobrien  root = n_array[ifun->eh->region_tree->region_number];
163390075Sobrien  cur = cfun->eh->cur_region;
163490075Sobrien  if (cur)
163590075Sobrien    {
163690075Sobrien      struct eh_region *p = cur->inner;
163790075Sobrien      if (p)
163890075Sobrien	{
163990075Sobrien	  while (p->next_peer)
164090075Sobrien	    p = p->next_peer;
164190075Sobrien	  p->next_peer = root;
164290075Sobrien	}
164390075Sobrien      else
164490075Sobrien	cur->inner = root;
164550397Sobrien
164690075Sobrien      for (i = 1; i <= ifun_last_region_number; ++i)
164790075Sobrien	if (n_array[i] && n_array[i]->outer == NULL)
164890075Sobrien	  n_array[i]->outer = cur;
164990075Sobrien    }
165090075Sobrien  else
165190075Sobrien    {
165290075Sobrien      struct eh_region *p = cfun->eh->region_tree;
165390075Sobrien      if (p)
165490075Sobrien	{
165590075Sobrien	  while (p->next_peer)
165690075Sobrien	    p = p->next_peer;
165790075Sobrien	  p->next_peer = root;
165890075Sobrien	}
165990075Sobrien      else
166090075Sobrien	cfun->eh->region_tree = root;
166190075Sobrien    }
166250397Sobrien
166390075Sobrien  free (n_array);
166450397Sobrien
166590075Sobrien  i = cfun->eh->last_region_number;
166690075Sobrien  cfun->eh->last_region_number = i + ifun_last_region_number;
166790075Sobrien  return i;
166890075Sobrien}
166950397Sobrien
167090075Sobrien
167190075Sobrienstatic int
167290075Sobrient2r_eq (pentry, pdata)
167390075Sobrien     const PTR pentry;
167490075Sobrien     const PTR pdata;
167590075Sobrien{
167690075Sobrien  tree entry = (tree) pentry;
167790075Sobrien  tree data = (tree) pdata;
167850397Sobrien
167990075Sobrien  return TREE_PURPOSE (entry) == data;
168090075Sobrien}
168150397Sobrien
168290075Sobrienstatic hashval_t
168390075Sobrient2r_hash (pentry)
168490075Sobrien     const PTR pentry;
168590075Sobrien{
168690075Sobrien  tree entry = (tree) pentry;
168790075Sobrien  return TYPE_HASH (TREE_PURPOSE (entry));
168850397Sobrien}
168950397Sobrien
169090075Sobrienstatic int
169190075Sobrient2r_mark_1 (slot, data)
169290075Sobrien     PTR *slot;
169390075Sobrien     PTR data ATTRIBUTE_UNUSED;
169490075Sobrien{
169590075Sobrien  tree contents = (tree) *slot;
169690075Sobrien  ggc_mark_tree (contents);
169790075Sobrien  return 1;
169890075Sobrien}
169950397Sobrien
170050397Sobrienstatic void
170190075Sobrient2r_mark (addr)
170290075Sobrien     PTR addr;
170350397Sobrien{
170490075Sobrien  htab_traverse (*(htab_t *)addr, t2r_mark_1, NULL);
170590075Sobrien}
170650397Sobrien
170790075Sobrienstatic void
170890075Sobrienadd_type_for_runtime (type)
170990075Sobrien     tree type;
171090075Sobrien{
171190075Sobrien  tree *slot;
171250397Sobrien
171390075Sobrien  slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
171490075Sobrien					    TYPE_HASH (type), INSERT);
171590075Sobrien  if (*slot == NULL)
171690075Sobrien    {
171790075Sobrien      tree runtime = (*lang_eh_runtime_type) (type);
171890075Sobrien      *slot = tree_cons (type, runtime, NULL_TREE);
171990075Sobrien    }
172090075Sobrien}
172150397Sobrien
172290075Sobrienstatic tree
172390075Sobrienlookup_type_for_runtime (type)
172490075Sobrien     tree type;
172590075Sobrien{
172690075Sobrien  tree *slot;
172750397Sobrien
172890075Sobrien  slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
172990075Sobrien					    TYPE_HASH (type), NO_INSERT);
173050397Sobrien
173190075Sobrien  /* We should have always inserted the data earlier.  */
173290075Sobrien  return TREE_VALUE (*slot);
173390075Sobrien}
173450397Sobrien
173590075Sobrien
173690075Sobrien/* Represent an entry in @TTypes for either catch actions
173790075Sobrien   or exception filter actions.  */
173890075Sobrienstruct ttypes_filter
173990075Sobrien{
174090075Sobrien  tree t;
174190075Sobrien  int filter;
174290075Sobrien};
174350397Sobrien
174490075Sobrien/* Compare ENTRY (a ttypes_filter entry in the hash table) with DATA
174590075Sobrien   (a tree) for a @TTypes type node we are thinking about adding.  */
174650397Sobrien
174790075Sobrienstatic int
174890075Sobrienttypes_filter_eq (pentry, pdata)
174990075Sobrien     const PTR pentry;
175090075Sobrien     const PTR pdata;
175190075Sobrien{
175290075Sobrien  const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
175390075Sobrien  tree data = (tree) pdata;
175450397Sobrien
175590075Sobrien  return entry->t == data;
175650397Sobrien}
175750397Sobrien
175890075Sobrienstatic hashval_t
175990075Sobrienttypes_filter_hash (pentry)
176090075Sobrien     const PTR pentry;
176190075Sobrien{
176290075Sobrien  const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
176390075Sobrien  return TYPE_HASH (entry->t);
176490075Sobrien}
176550397Sobrien
176690075Sobrien/* Compare ENTRY with DATA (both struct ttypes_filter) for a @TTypes
176790075Sobrien   exception specification list we are thinking about adding.  */
176890075Sobrien/* ??? Currently we use the type lists in the order given.  Someone
176990075Sobrien   should put these in some canonical order.  */
177050397Sobrien
177190075Sobrienstatic int
177290075Sobrienehspec_filter_eq (pentry, pdata)
177390075Sobrien     const PTR pentry;
177490075Sobrien     const PTR pdata;
177550397Sobrien{
177690075Sobrien  const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
177790075Sobrien  const struct ttypes_filter *data = (const struct ttypes_filter *) pdata;
177850397Sobrien
177990075Sobrien  return type_list_equal (entry->t, data->t);
178090075Sobrien}
178150397Sobrien
178290075Sobrien/* Hash function for exception specification lists.  */
178350397Sobrien
178490075Sobrienstatic hashval_t
178590075Sobrienehspec_filter_hash (pentry)
178690075Sobrien     const PTR pentry;
178790075Sobrien{
178890075Sobrien  const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
178990075Sobrien  hashval_t h = 0;
179090075Sobrien  tree list;
179150397Sobrien
179290075Sobrien  for (list = entry->t; list ; list = TREE_CHAIN (list))
179390075Sobrien    h = (h << 5) + (h >> 27) + TYPE_HASH (TREE_VALUE (list));
179490075Sobrien  return h;
179550397Sobrien}
179650397Sobrien
179790075Sobrien/* Add TYPE to cfun->eh->ttype_data, using TYPES_HASH to speed
179890075Sobrien   up the search.  Return the filter value to be used.  */
179950397Sobrien
180090075Sobrienstatic int
180190075Sobrienadd_ttypes_entry (ttypes_hash, type)
180290075Sobrien     htab_t ttypes_hash;
180390075Sobrien     tree type;
180450397Sobrien{
180590075Sobrien  struct ttypes_filter **slot, *n;
180650397Sobrien
180790075Sobrien  slot = (struct ttypes_filter **)
180890075Sobrien    htab_find_slot_with_hash (ttypes_hash, type, TYPE_HASH (type), INSERT);
180950397Sobrien
181090075Sobrien  if ((n = *slot) == NULL)
181150397Sobrien    {
181290075Sobrien      /* Filter value is a 1 based table index.  */
181350397Sobrien
181490075Sobrien      n = (struct ttypes_filter *) xmalloc (sizeof (*n));
181590075Sobrien      n->t = type;
181690075Sobrien      n->filter = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) + 1;
181790075Sobrien      *slot = n;
181850397Sobrien
181990075Sobrien      VARRAY_PUSH_TREE (cfun->eh->ttype_data, type);
182050397Sobrien    }
182150397Sobrien
182290075Sobrien  return n->filter;
182350397Sobrien}
182450397Sobrien
182590075Sobrien/* Add LIST to cfun->eh->ehspec_data, using EHSPEC_HASH and TYPES_HASH
182690075Sobrien   to speed up the search.  Return the filter value to be used.  */
182750397Sobrien
182890075Sobrienstatic int
182990075Sobrienadd_ehspec_entry (ehspec_hash, ttypes_hash, list)
183090075Sobrien     htab_t ehspec_hash;
183190075Sobrien     htab_t ttypes_hash;
183290075Sobrien     tree list;
183350397Sobrien{
183490075Sobrien  struct ttypes_filter **slot, *n;
183590075Sobrien  struct ttypes_filter dummy;
183650397Sobrien
183790075Sobrien  dummy.t = list;
183890075Sobrien  slot = (struct ttypes_filter **)
183990075Sobrien    htab_find_slot (ehspec_hash, &dummy, INSERT);
184050397Sobrien
184190075Sobrien  if ((n = *slot) == NULL)
184290075Sobrien    {
184390075Sobrien      /* Filter value is a -1 based byte index into a uleb128 buffer.  */
184450397Sobrien
184590075Sobrien      n = (struct ttypes_filter *) xmalloc (sizeof (*n));
184690075Sobrien      n->t = list;
184790075Sobrien      n->filter = -(VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) + 1);
184890075Sobrien      *slot = n;
184950397Sobrien
185090075Sobrien      /* Look up each type in the list and encode its filter
185190075Sobrien	 value as a uleb128.  Terminate the list with 0.  */
185290075Sobrien      for (; list ; list = TREE_CHAIN (list))
185390075Sobrien	push_uleb128 (&cfun->eh->ehspec_data,
185490075Sobrien		      add_ttypes_entry (ttypes_hash, TREE_VALUE (list)));
185590075Sobrien      VARRAY_PUSH_UCHAR (cfun->eh->ehspec_data, 0);
185690075Sobrien    }
185790075Sobrien
185890075Sobrien  return n->filter;
185990075Sobrien}
186090075Sobrien
186190075Sobrien/* Generate the action filter values to be used for CATCH and
186290075Sobrien   ALLOWED_EXCEPTIONS regions.  When using dwarf2 exception regions,
186390075Sobrien   we use lots of landing pads, and so every type or list can share
186490075Sobrien   the same filter value, which saves table space.  */
186590075Sobrien
186690075Sobrienstatic void
186790075Sobrienassign_filter_values ()
186850397Sobrien{
186990075Sobrien  int i;
187090075Sobrien  htab_t ttypes, ehspec;
187150397Sobrien
187290075Sobrien  VARRAY_TREE_INIT (cfun->eh->ttype_data, 16, "ttype_data");
187390075Sobrien  VARRAY_UCHAR_INIT (cfun->eh->ehspec_data, 64, "ehspec_data");
187450397Sobrien
187590075Sobrien  ttypes = htab_create (31, ttypes_filter_hash, ttypes_filter_eq, free);
187690075Sobrien  ehspec = htab_create (31, ehspec_filter_hash, ehspec_filter_eq, free);
187750397Sobrien
187890075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
187950397Sobrien    {
188090075Sobrien      struct eh_region *r = cfun->eh->region_array[i];
188150397Sobrien
188290075Sobrien      /* Mind we don't process a region more than once.  */
188390075Sobrien      if (!r || r->region_number != i)
188490075Sobrien	continue;
188550397Sobrien
188690075Sobrien      switch (r->type)
188790075Sobrien	{
188890075Sobrien	case ERT_CATCH:
188990075Sobrien	  /* Whatever type_list is (NULL or true list), we build a list
189090075Sobrien	     of filters for the region.  */
189190075Sobrien	  r->u.catch.filter_list = NULL_TREE;
189250397Sobrien
189390075Sobrien	  if (r->u.catch.type_list != NULL)
189490075Sobrien	    {
189590075Sobrien	      /* Get a filter value for each of the types caught and store
189690075Sobrien		 them in the region's dedicated list.  */
189790075Sobrien	      tree tp_node = r->u.catch.type_list;
189850397Sobrien
189990075Sobrien	      for (;tp_node; tp_node = TREE_CHAIN (tp_node))
190090075Sobrien		{
190190075Sobrien		  int flt = add_ttypes_entry (ttypes, TREE_VALUE (tp_node));
190290075Sobrien		  tree flt_node = build_int_2 (flt, 0);
190350397Sobrien
190490075Sobrien		  r->u.catch.filter_list
190590075Sobrien		    = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list);
190690075Sobrien		}
190790075Sobrien	    }
190890075Sobrien	  else
190990075Sobrien	    {
191090075Sobrien	      /* Get a filter value for the NULL list also since it will need
191190075Sobrien		 an action record anyway.  */
191290075Sobrien	      int flt = add_ttypes_entry (ttypes, NULL);
191390075Sobrien	      tree flt_node = build_int_2 (flt, 0);
191450397Sobrien
191590075Sobrien	      r->u.catch.filter_list
191690075Sobrien		= tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list);
191790075Sobrien	    }
191850397Sobrien
191990075Sobrien	  break;
192050397Sobrien
192190075Sobrien	case ERT_ALLOWED_EXCEPTIONS:
192290075Sobrien	  r->u.allowed.filter
192390075Sobrien	    = add_ehspec_entry (ehspec, ttypes, r->u.allowed.type_list);
192490075Sobrien	  break;
192550397Sobrien
192690075Sobrien	default:
192790075Sobrien	  break;
192890075Sobrien	}
192950397Sobrien    }
193090075Sobrien
193190075Sobrien  htab_delete (ttypes);
193290075Sobrien  htab_delete (ehspec);
193350397Sobrien}
193450397Sobrien
193590075Sobrienstatic void
193690075Sobrienbuild_post_landing_pads ()
193750397Sobrien{
193890075Sobrien  int i;
193950397Sobrien
194090075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
194190075Sobrien    {
194290075Sobrien      struct eh_region *region = cfun->eh->region_array[i];
194390075Sobrien      rtx seq;
194450397Sobrien
194590075Sobrien      /* Mind we don't process a region more than once.  */
194690075Sobrien      if (!region || region->region_number != i)
194790075Sobrien	continue;
194850397Sobrien
194990075Sobrien      switch (region->type)
195090075Sobrien	{
195190075Sobrien	case ERT_TRY:
195290075Sobrien	  /* ??? Collect the set of all non-overlapping catch handlers
195390075Sobrien	       all the way up the chain until blocked by a cleanup.  */
195490075Sobrien	  /* ??? Outer try regions can share landing pads with inner
195590075Sobrien	     try regions if the types are completely non-overlapping,
195690075Sobrien	     and there are no intervening cleanups.  */
195750397Sobrien
195890075Sobrien	  region->post_landing_pad = gen_label_rtx ();
195950397Sobrien
196090075Sobrien	  start_sequence ();
196150397Sobrien
196290075Sobrien	  emit_label (region->post_landing_pad);
196350397Sobrien
196490075Sobrien	  /* ??? It is mighty inconvenient to call back into the
196590075Sobrien	     switch statement generation code in expand_end_case.
196690075Sobrien	     Rapid prototyping sez a sequence of ifs.  */
196790075Sobrien	  {
196890075Sobrien	    struct eh_region *c;
196990075Sobrien	    for (c = region->u.try.catch; c ; c = c->u.catch.next_catch)
197090075Sobrien	      {
197190075Sobrien		/* ??? _Unwind_ForcedUnwind wants no match here.  */
197290075Sobrien		if (c->u.catch.type_list == NULL)
197390075Sobrien		  emit_jump (c->label);
197490075Sobrien		else
197590075Sobrien		  {
197690075Sobrien		    /* Need for one cmp/jump per type caught. Each type
197790075Sobrien		       list entry has a matching entry in the filter list
197890075Sobrien		       (see assign_filter_values).  */
197990075Sobrien		    tree tp_node = c->u.catch.type_list;
198090075Sobrien		    tree flt_node = c->u.catch.filter_list;
198150397Sobrien
198290075Sobrien		    for (; tp_node; )
198390075Sobrien		      {
198490075Sobrien			emit_cmp_and_jump_insns
198590075Sobrien			  (cfun->eh->filter,
198690075Sobrien			   GEN_INT (tree_low_cst (TREE_VALUE (flt_node), 0)),
198790075Sobrien			   EQ, NULL_RTX, word_mode, 0, c->label);
198850397Sobrien
198990075Sobrien			tp_node = TREE_CHAIN (tp_node);
199090075Sobrien			flt_node = TREE_CHAIN (flt_node);
199190075Sobrien		      }
199290075Sobrien		  }
199390075Sobrien	      }
199490075Sobrien	  }
199550397Sobrien
199690075Sobrien	  /* We delay the generation of the _Unwind_Resume until we generate
199790075Sobrien	     landing pads.  We emit a marker here so as to get good control
199890075Sobrien	     flow data in the meantime.  */
199990075Sobrien	  region->resume
200090075Sobrien	    = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
200190075Sobrien	  emit_barrier ();
200250397Sobrien
200390075Sobrien	  seq = get_insns ();
200490075Sobrien	  end_sequence ();
200550397Sobrien
200690075Sobrien	  emit_insns_before (seq, region->u.try.catch->label);
200790075Sobrien	  break;
200850397Sobrien
200990075Sobrien	case ERT_ALLOWED_EXCEPTIONS:
201090075Sobrien	  region->post_landing_pad = gen_label_rtx ();
201150397Sobrien
201290075Sobrien	  start_sequence ();
201350397Sobrien
201490075Sobrien	  emit_label (region->post_landing_pad);
201550397Sobrien
201690075Sobrien	  emit_cmp_and_jump_insns (cfun->eh->filter,
201790075Sobrien				   GEN_INT (region->u.allowed.filter),
201890075Sobrien				   EQ, NULL_RTX, word_mode, 0, region->label);
201950397Sobrien
202090075Sobrien	  /* We delay the generation of the _Unwind_Resume until we generate
202190075Sobrien	     landing pads.  We emit a marker here so as to get good control
202290075Sobrien	     flow data in the meantime.  */
202390075Sobrien	  region->resume
202490075Sobrien	    = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
202590075Sobrien	  emit_barrier ();
202650397Sobrien
202790075Sobrien	  seq = get_insns ();
202890075Sobrien	  end_sequence ();
202990075Sobrien
203090075Sobrien	  emit_insns_before (seq, region->label);
203190075Sobrien	  break;
203290075Sobrien
203390075Sobrien	case ERT_CLEANUP:
203490075Sobrien	case ERT_MUST_NOT_THROW:
203590075Sobrien	  region->post_landing_pad = region->label;
203690075Sobrien	  break;
203790075Sobrien
203890075Sobrien	case ERT_CATCH:
203990075Sobrien	case ERT_THROW:
204090075Sobrien	  /* Nothing to do.  */
204190075Sobrien	  break;
204290075Sobrien
204390075Sobrien	default:
204490075Sobrien	  abort ();
204590075Sobrien	}
204690075Sobrien    }
204750397Sobrien}
204850397Sobrien
204990075Sobrien/* Replace RESX patterns with jumps to the next handler if any, or calls to
205090075Sobrien   _Unwind_Resume otherwise.  */
205150397Sobrien
205290075Sobrienstatic void
205390075Sobrienconnect_post_landing_pads ()
205450397Sobrien{
205590075Sobrien  int i;
205650397Sobrien
205790075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
205850397Sobrien    {
205990075Sobrien      struct eh_region *region = cfun->eh->region_array[i];
206090075Sobrien      struct eh_region *outer;
206190075Sobrien      rtx seq;
206250397Sobrien
206390075Sobrien      /* Mind we don't process a region more than once.  */
206490075Sobrien      if (!region || region->region_number != i)
206590075Sobrien	continue;
206650397Sobrien
206790075Sobrien      /* If there is no RESX, or it has been deleted by flow, there's
206890075Sobrien	 nothing to fix up.  */
206990075Sobrien      if (! region->resume || INSN_DELETED_P (region->resume))
207090075Sobrien	continue;
207150397Sobrien
207290075Sobrien      /* Search for another landing pad in this function.  */
207390075Sobrien      for (outer = region->outer; outer ; outer = outer->outer)
207490075Sobrien	if (outer->post_landing_pad)
207590075Sobrien	  break;
207650397Sobrien
207790075Sobrien      start_sequence ();
207850397Sobrien
207990075Sobrien      if (outer)
208090075Sobrien	emit_jump (outer->post_landing_pad);
208190075Sobrien      else
208290075Sobrien	emit_library_call (unwind_resume_libfunc, LCT_THROW,
208390075Sobrien			   VOIDmode, 1, cfun->eh->exc_ptr, Pmode);
208450397Sobrien
208590075Sobrien      seq = get_insns ();
208690075Sobrien      end_sequence ();
208790075Sobrien      emit_insns_before (seq, region->resume);
208890075Sobrien      delete_insn (region->resume);
208950397Sobrien    }
209050397Sobrien}
209150397Sobrien
209290075Sobrien
209390075Sobrienstatic void
209490075Sobriendw2_build_landing_pads ()
209550397Sobrien{
209690075Sobrien  int i;
209790075Sobrien  unsigned int j;
209850397Sobrien
209990075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
210090075Sobrien    {
210190075Sobrien      struct eh_region *region = cfun->eh->region_array[i];
210290075Sobrien      rtx seq;
210390075Sobrien      bool clobbers_hard_regs = false;
210450397Sobrien
210590075Sobrien      /* Mind we don't process a region more than once.  */
210690075Sobrien      if (!region || region->region_number != i)
210790075Sobrien	continue;
210850397Sobrien
210990075Sobrien      if (region->type != ERT_CLEANUP
211090075Sobrien	  && region->type != ERT_TRY
211190075Sobrien	  && region->type != ERT_ALLOWED_EXCEPTIONS)
211290075Sobrien	continue;
211350397Sobrien
211490075Sobrien      start_sequence ();
211550397Sobrien
211690075Sobrien      region->landing_pad = gen_label_rtx ();
211790075Sobrien      emit_label (region->landing_pad);
211850397Sobrien
211990075Sobrien#ifdef HAVE_exception_receiver
212090075Sobrien      if (HAVE_exception_receiver)
212190075Sobrien	emit_insn (gen_exception_receiver ());
212290075Sobrien      else
212390075Sobrien#endif
212490075Sobrien#ifdef HAVE_nonlocal_goto_receiver
212590075Sobrien	if (HAVE_nonlocal_goto_receiver)
212690075Sobrien	  emit_insn (gen_nonlocal_goto_receiver ());
212790075Sobrien	else
212890075Sobrien#endif
212990075Sobrien	  { /* Nothing */ }
213050397Sobrien
213190075Sobrien      /* If the eh_return data registers are call-saved, then we
213290075Sobrien	 won't have considered them clobbered from the call that
213390075Sobrien	 threw.  Kill them now.  */
213490075Sobrien      for (j = 0; ; ++j)
213590075Sobrien	{
213690075Sobrien	  unsigned r = EH_RETURN_DATA_REGNO (j);
213790075Sobrien	  if (r == INVALID_REGNUM)
213890075Sobrien	    break;
213990075Sobrien	  if (! call_used_regs[r])
214090075Sobrien	    {
214190075Sobrien	      emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, r)));
214290075Sobrien	      clobbers_hard_regs = true;
214390075Sobrien	    }
214490075Sobrien	}
214552284Sobrien
214690075Sobrien      if (clobbers_hard_regs)
214790075Sobrien	{
214890075Sobrien	  /* @@@ This is a kludge.  Not all machine descriptions define a
214990075Sobrien	     blockage insn, but we must not allow the code we just generated
215090075Sobrien	     to be reordered by scheduling.  So emit an ASM_INPUT to act as
215190075Sobrien	     blockage insn.  */
215290075Sobrien	  emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
215390075Sobrien	}
215452284Sobrien
215590075Sobrien      emit_move_insn (cfun->eh->exc_ptr,
215690075Sobrien		      gen_rtx_REG (Pmode, EH_RETURN_DATA_REGNO (0)));
215790075Sobrien      emit_move_insn (cfun->eh->filter,
215890075Sobrien		      gen_rtx_REG (word_mode, EH_RETURN_DATA_REGNO (1)));
215952284Sobrien
216090075Sobrien      seq = get_insns ();
216190075Sobrien      end_sequence ();
216252284Sobrien
216390075Sobrien      emit_insns_before (seq, region->post_landing_pad);
216452284Sobrien    }
216550397Sobrien}
216650397Sobrien
216790075Sobrien
216890075Sobrienstruct sjlj_lp_info
216990075Sobrien{
217090075Sobrien  int directly_reachable;
217190075Sobrien  int action_index;
217290075Sobrien  int dispatch_index;
217390075Sobrien  int call_site_index;
217490075Sobrien};
217552284Sobrien
217690075Sobrienstatic bool
217790075Sobriensjlj_find_directly_reachable_regions (lp_info)
217890075Sobrien     struct sjlj_lp_info *lp_info;
217952284Sobrien{
218090075Sobrien  rtx insn;
218190075Sobrien  bool found_one = false;
218252284Sobrien
218390075Sobrien  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
218452284Sobrien    {
218590075Sobrien      struct eh_region *region;
218690075Sobrien      enum reachable_code rc;
218790075Sobrien      tree type_thrown;
218890075Sobrien      rtx note;
218990075Sobrien
219090075Sobrien      if (! INSN_P (insn))
219190075Sobrien	continue;
219290075Sobrien
219390075Sobrien      note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
219490075Sobrien      if (!note || INTVAL (XEXP (note, 0)) <= 0)
219590075Sobrien	continue;
219690075Sobrien
219790075Sobrien      region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
219890075Sobrien
219990075Sobrien      type_thrown = NULL_TREE;
220090075Sobrien      if (region->type == ERT_THROW)
220190075Sobrien	{
220290075Sobrien	  type_thrown = region->u.throw.type;
220390075Sobrien	  region = region->outer;
220490075Sobrien	}
220590075Sobrien
220690075Sobrien      /* Find the first containing region that might handle the exception.
220790075Sobrien	 That's the landing pad to which we will transfer control.  */
220890075Sobrien      rc = RNL_NOT_CAUGHT;
220990075Sobrien      for (; region; region = region->outer)
221090075Sobrien	{
221190075Sobrien	  rc = reachable_next_level (region, type_thrown, 0);
221290075Sobrien	  if (rc != RNL_NOT_CAUGHT)
221390075Sobrien	    break;
221490075Sobrien	}
221590075Sobrien      if (rc == RNL_MAYBE_CAUGHT || rc == RNL_CAUGHT)
221690075Sobrien	{
221790075Sobrien	  lp_info[region->region_number].directly_reachable = 1;
221890075Sobrien	  found_one = true;
221990075Sobrien	}
222052284Sobrien    }
222152284Sobrien
222290075Sobrien  return found_one;
222352284Sobrien}
222452284Sobrien
222590075Sobrienstatic void
222690075Sobriensjlj_assign_call_site_values (dispatch_label, lp_info)
222790075Sobrien     rtx dispatch_label;
222890075Sobrien     struct sjlj_lp_info *lp_info;
222990075Sobrien{
223090075Sobrien  htab_t ar_hash;
223190075Sobrien  int i, index;
223250397Sobrien
223390075Sobrien  /* First task: build the action table.  */
223450397Sobrien
223590075Sobrien  VARRAY_UCHAR_INIT (cfun->eh->action_record_data, 64, "action_record_data");
223690075Sobrien  ar_hash = htab_create (31, action_record_hash, action_record_eq, free);
223750397Sobrien
223890075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
223990075Sobrien    if (lp_info[i].directly_reachable)
224090075Sobrien      {
224190075Sobrien	struct eh_region *r = cfun->eh->region_array[i];
224290075Sobrien	r->landing_pad = dispatch_label;
224390075Sobrien	lp_info[i].action_index = collect_one_action_chain (ar_hash, r);
224490075Sobrien	if (lp_info[i].action_index != -1)
224590075Sobrien	  cfun->uses_eh_lsda = 1;
224690075Sobrien      }
224750397Sobrien
224890075Sobrien  htab_delete (ar_hash);
224950397Sobrien
225090075Sobrien  /* Next: assign dispatch values.  In dwarf2 terms, this would be the
225190075Sobrien     landing pad label for the region.  For sjlj though, there is one
225290075Sobrien     common landing pad from which we dispatch to the post-landing pads.
225350397Sobrien
225490075Sobrien     A region receives a dispatch index if it is directly reachable
225590075Sobrien     and requires in-function processing.  Regions that share post-landing
225690075Sobrien     pads may share dispatch indices.  */
225790075Sobrien  /* ??? Post-landing pad sharing doesn't actually happen at the moment
225890075Sobrien     (see build_post_landing_pads) so we don't bother checking for it.  */
225950397Sobrien
226090075Sobrien  index = 0;
226190075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
226290075Sobrien    if (lp_info[i].directly_reachable)
226390075Sobrien      lp_info[i].dispatch_index = index++;
226450397Sobrien
226590075Sobrien  /* Finally: assign call-site values.  If dwarf2 terms, this would be
226690075Sobrien     the region number assigned by convert_to_eh_region_ranges, but
226790075Sobrien     handles no-action and must-not-throw differently.  */
226850397Sobrien
226990075Sobrien  call_site_base = 1;
227090075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
227190075Sobrien    if (lp_info[i].directly_reachable)
227290075Sobrien      {
227390075Sobrien	int action = lp_info[i].action_index;
227490075Sobrien
227590075Sobrien	/* Map must-not-throw to otherwise unused call-site index 0.  */
227690075Sobrien	if (action == -2)
227790075Sobrien	  index = 0;
227890075Sobrien	/* Map no-action to otherwise unused call-site index -1.  */
227990075Sobrien	else if (action == -1)
228090075Sobrien	  index = -1;
228190075Sobrien	/* Otherwise, look it up in the table.  */
228290075Sobrien	else
228390075Sobrien	  index = add_call_site (GEN_INT (lp_info[i].dispatch_index), action);
228490075Sobrien
228590075Sobrien	lp_info[i].call_site_index = index;
228690075Sobrien      }
228790075Sobrien}
228890075Sobrien
228990075Sobrienstatic void
229090075Sobriensjlj_mark_call_sites (lp_info)
229190075Sobrien     struct sjlj_lp_info *lp_info;
229290075Sobrien{
229390075Sobrien  int last_call_site = -2;
229490075Sobrien  rtx insn, mem;
229590075Sobrien
229690075Sobrien  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
229750397Sobrien    {
229890075Sobrien      struct eh_region *region;
229990075Sobrien      int this_call_site;
230090075Sobrien      rtx note, before, p;
230150397Sobrien
230290075Sobrien      /* Reset value tracking at extended basic block boundaries.  */
230390075Sobrien      if (GET_CODE (insn) == CODE_LABEL)
230490075Sobrien	last_call_site = -2;
230550397Sobrien
230690075Sobrien      if (! INSN_P (insn))
230790075Sobrien	continue;
230850397Sobrien
230990075Sobrien      note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
231090075Sobrien      if (!note)
231190075Sobrien	{
231290075Sobrien	  /* Calls (and trapping insns) without notes are outside any
231390075Sobrien	     exception handling region in this function.  Mark them as
231490075Sobrien	     no action.  */
231590075Sobrien	  if (GET_CODE (insn) == CALL_INSN
231690075Sobrien	      || (flag_non_call_exceptions
231790075Sobrien		  && may_trap_p (PATTERN (insn))))
231890075Sobrien	    this_call_site = -1;
231990075Sobrien	  else
232090075Sobrien	    continue;
232190075Sobrien	}
232290075Sobrien      else
232390075Sobrien	{
232490075Sobrien	  /* Calls that are known to not throw need not be marked.  */
232590075Sobrien	  if (INTVAL (XEXP (note, 0)) <= 0)
232690075Sobrien	    continue;
232750397Sobrien
232890075Sobrien	  region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
232990075Sobrien	  this_call_site = lp_info[region->region_number].call_site_index;
233090075Sobrien	}
233150397Sobrien
233290075Sobrien      if (this_call_site == last_call_site)
233390075Sobrien	continue;
233450397Sobrien
233590075Sobrien      /* Don't separate a call from it's argument loads.  */
233690075Sobrien      before = insn;
233790075Sobrien      if (GET_CODE (insn) == CALL_INSN)
233890075Sobrien         before = find_first_parameter_load (insn, NULL_RTX);
233950397Sobrien
234090075Sobrien      start_sequence ();
234190075Sobrien      mem = adjust_address (cfun->eh->sjlj_fc, TYPE_MODE (integer_type_node),
234290075Sobrien			    sjlj_fc_call_site_ofs);
234390075Sobrien      emit_move_insn (mem, GEN_INT (this_call_site));
234490075Sobrien      p = get_insns ();
234590075Sobrien      end_sequence ();
234650397Sobrien
234790075Sobrien      emit_insns_before (p, before);
234890075Sobrien      last_call_site = this_call_site;
234950397Sobrien    }
235050397Sobrien}
235150397Sobrien
235290075Sobrien/* Construct the SjLj_Function_Context.  */
235350397Sobrien
235490075Sobrienstatic void
235590075Sobriensjlj_emit_function_enter (dispatch_label)
235690075Sobrien     rtx dispatch_label;
235750397Sobrien{
235890075Sobrien  rtx fn_begin, fc, mem, seq;
235950397Sobrien
236090075Sobrien  fc = cfun->eh->sjlj_fc;
236150397Sobrien
236290075Sobrien  start_sequence ();
236350397Sobrien
236490075Sobrien  /* We're storing this libcall's address into memory instead of
236590075Sobrien     calling it directly.  Thus, we must call assemble_external_libcall
236690075Sobrien     here, as we can not depend on emit_library_call to do it for us.  */
236790075Sobrien  assemble_external_libcall (eh_personality_libfunc);
236890075Sobrien  mem = adjust_address (fc, Pmode, sjlj_fc_personality_ofs);
236990075Sobrien  emit_move_insn (mem, eh_personality_libfunc);
237090075Sobrien
237190075Sobrien  mem = adjust_address (fc, Pmode, sjlj_fc_lsda_ofs);
237290075Sobrien  if (cfun->uses_eh_lsda)
237350397Sobrien    {
237490075Sobrien      char buf[20];
237590075Sobrien      ASM_GENERATE_INTERNAL_LABEL (buf, "LLSDA", sjlj_funcdef_number);
237690075Sobrien      emit_move_insn (mem, gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)));
237750397Sobrien    }
237890075Sobrien  else
237990075Sobrien    emit_move_insn (mem, const0_rtx);
238050397Sobrien
238190075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP
238290075Sobrien  {
238390075Sobrien    rtx x, note;
238490075Sobrien    x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_RETURNS_TWICE,
238590075Sobrien				 TYPE_MODE (integer_type_node), 1,
238690075Sobrien				 plus_constant (XEXP (fc, 0),
238790075Sobrien						sjlj_fc_jbuf_ofs), Pmode);
238850397Sobrien
238990075Sobrien    note = emit_note (NULL, NOTE_INSN_EXPECTED_VALUE);
239090075Sobrien    NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, x, const0_rtx);
239150397Sobrien
239290075Sobrien    emit_cmp_and_jump_insns (x, const0_rtx, NE, 0,
239390075Sobrien			     TYPE_MODE (integer_type_node), 0, dispatch_label);
239490075Sobrien  }
239590075Sobrien#else
239690075Sobrien  expand_builtin_setjmp_setup (plus_constant (XEXP (fc, 0), sjlj_fc_jbuf_ofs),
239790075Sobrien			       dispatch_label);
239890075Sobrien#endif
239950397Sobrien
240090075Sobrien  emit_library_call (unwind_sjlj_register_libfunc, LCT_NORMAL, VOIDmode,
240190075Sobrien		     1, XEXP (fc, 0), Pmode);
240290075Sobrien
240390075Sobrien  seq = get_insns ();
240450397Sobrien  end_sequence ();
240550397Sobrien
240690075Sobrien  /* ??? Instead of doing this at the beginning of the function,
240790075Sobrien     do this in a block that is at loop level 0 and dominates all
240890075Sobrien     can_throw_internal instructions.  */
240950397Sobrien
241090075Sobrien  for (fn_begin = get_insns (); ; fn_begin = NEXT_INSN (fn_begin))
241190075Sobrien    if (GET_CODE (fn_begin) == NOTE
241290075Sobrien	&& NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG)
241390075Sobrien      break;
241490075Sobrien  emit_insns_after (seq, fn_begin);
241550397Sobrien}
241650397Sobrien
241790075Sobrien/* Call back from expand_function_end to know where we should put
241890075Sobrien   the call to unwind_sjlj_unregister_libfunc if needed.  */
241950397Sobrien
242050397Sobrienvoid
242190075Sobriensjlj_emit_function_exit_after (after)
242290075Sobrien     rtx after;
242350397Sobrien{
242490075Sobrien  cfun->eh->sjlj_exit_after = after;
242550397Sobrien}
242650397Sobrien
242790075Sobrienstatic void
242890075Sobriensjlj_emit_function_exit ()
242950397Sobrien{
243090075Sobrien  rtx seq;
243150397Sobrien
243290075Sobrien  start_sequence ();
243350397Sobrien
243490075Sobrien  emit_library_call (unwind_sjlj_unregister_libfunc, LCT_NORMAL, VOIDmode,
243590075Sobrien		     1, XEXP (cfun->eh->sjlj_fc, 0), Pmode);
243650397Sobrien
243790075Sobrien  seq = get_insns ();
243890075Sobrien  end_sequence ();
243950397Sobrien
244090075Sobrien  /* ??? Really this can be done in any block at loop level 0 that
244190075Sobrien     post-dominates all can_throw_internal instructions.  This is
244290075Sobrien     the last possible moment.  */
244350397Sobrien
244490075Sobrien  emit_insns_after (seq, cfun->eh->sjlj_exit_after);
244590075Sobrien}
244650397Sobrien
244790075Sobrienstatic void
244890075Sobriensjlj_emit_dispatch_table (dispatch_label, lp_info)
244990075Sobrien     rtx dispatch_label;
245090075Sobrien     struct sjlj_lp_info *lp_info;
245190075Sobrien{
245290075Sobrien  int i, first_reachable;
245390075Sobrien  rtx mem, dispatch, seq, fc;
245450397Sobrien
245590075Sobrien  fc = cfun->eh->sjlj_fc;
245650397Sobrien
245790075Sobrien  start_sequence ();
245850397Sobrien
245990075Sobrien  emit_label (dispatch_label);
246050397Sobrien
246190075Sobrien#ifndef DONT_USE_BUILTIN_SETJMP
246290075Sobrien  expand_builtin_setjmp_receiver (dispatch_label);
246390075Sobrien#endif
246450397Sobrien
246590075Sobrien  /* Load up dispatch index, exc_ptr and filter values from the
246690075Sobrien     function context.  */
246790075Sobrien  mem = adjust_address (fc, TYPE_MODE (integer_type_node),
246890075Sobrien			sjlj_fc_call_site_ofs);
246990075Sobrien  dispatch = copy_to_reg (mem);
247050397Sobrien
247190075Sobrien  mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs);
247290075Sobrien  if (word_mode != Pmode)
247350397Sobrien    {
247490075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED
247590075Sobrien      mem = convert_memory_address (Pmode, mem);
247690075Sobrien#else
247790075Sobrien      mem = convert_to_mode (Pmode, mem, 0);
247890075Sobrien#endif
247990075Sobrien    }
248090075Sobrien  emit_move_insn (cfun->eh->exc_ptr, mem);
248150397Sobrien
248290075Sobrien  mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs + UNITS_PER_WORD);
248390075Sobrien  emit_move_insn (cfun->eh->filter, mem);
248450397Sobrien
248590075Sobrien  /* Jump to one of the directly reachable regions.  */
248690075Sobrien  /* ??? This really ought to be using a switch statement.  */
248790075Sobrien
248890075Sobrien  first_reachable = 0;
248990075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
249090075Sobrien    {
249190075Sobrien      if (! lp_info[i].directly_reachable)
249290075Sobrien	continue;
249390075Sobrien
249490075Sobrien      if (! first_reachable)
249550397Sobrien	{
249690075Sobrien	  first_reachable = i;
249790075Sobrien	  continue;
249850397Sobrien	}
249990075Sobrien
250090075Sobrien      emit_cmp_and_jump_insns (dispatch, GEN_INT (lp_info[i].dispatch_index),
250190075Sobrien			       EQ, NULL_RTX, TYPE_MODE (integer_type_node), 0,
250290075Sobrien			       cfun->eh->region_array[i]->post_landing_pad);
250350397Sobrien    }
250450397Sobrien
250590075Sobrien  seq = get_insns ();
250690075Sobrien  end_sequence ();
250750397Sobrien
250890075Sobrien  emit_insns_before (seq, (cfun->eh->region_array[first_reachable]
250990075Sobrien			   ->post_landing_pad));
251050397Sobrien}
251150397Sobrien
251250397Sobrienstatic void
251390075Sobriensjlj_build_landing_pads ()
251450397Sobrien{
251590075Sobrien  struct sjlj_lp_info *lp_info;
251650397Sobrien
251790075Sobrien  lp_info = (struct sjlj_lp_info *) xcalloc (cfun->eh->last_region_number + 1,
251890075Sobrien					     sizeof (struct sjlj_lp_info));
251950397Sobrien
252090075Sobrien  if (sjlj_find_directly_reachable_regions (lp_info))
252150397Sobrien    {
252290075Sobrien      rtx dispatch_label = gen_label_rtx ();
252352284Sobrien
252490075Sobrien      cfun->eh->sjlj_fc
252590075Sobrien	= assign_stack_local (TYPE_MODE (sjlj_fc_type_node),
252690075Sobrien			      int_size_in_bytes (sjlj_fc_type_node),
252790075Sobrien			      TYPE_ALIGN (sjlj_fc_type_node));
252850397Sobrien
252990075Sobrien      sjlj_assign_call_site_values (dispatch_label, lp_info);
253090075Sobrien      sjlj_mark_call_sites (lp_info);
253150397Sobrien
253290075Sobrien      sjlj_emit_function_enter (dispatch_label);
253390075Sobrien      sjlj_emit_dispatch_table (dispatch_label, lp_info);
253490075Sobrien      sjlj_emit_function_exit ();
253550397Sobrien    }
253650397Sobrien
253790075Sobrien  free (lp_info);
253850397Sobrien}
253950397Sobrien
254052284Sobrienvoid
254190075Sobrienfinish_eh_generation ()
254250397Sobrien{
254390075Sobrien  /* Nothing to do if no regions created.  */
254490075Sobrien  if (cfun->eh->region_tree == NULL)
254590075Sobrien    return;
254650397Sobrien
254790075Sobrien  /* The object here is to provide find_basic_blocks with detailed
254890075Sobrien     information (via reachable_handlers) on how exception control
254990075Sobrien     flows within the function.  In this first pass, we can include
255090075Sobrien     type information garnered from ERT_THROW and ERT_ALLOWED_EXCEPTIONS
255190075Sobrien     regions, and hope that it will be useful in deleting unreachable
255290075Sobrien     handlers.  Subsequently, we will generate landing pads which will
255390075Sobrien     connect many of the handlers, and then type information will not
255490075Sobrien     be effective.  Still, this is a win over previous implementations.  */
255550397Sobrien
255690075Sobrien  rebuild_jump_labels (get_insns ());
255790075Sobrien  find_basic_blocks (get_insns (), max_reg_num (), 0);
255890075Sobrien  cleanup_cfg (CLEANUP_PRE_LOOP);
255950397Sobrien
256090075Sobrien  /* These registers are used by the landing pads.  Make sure they
256190075Sobrien     have been generated.  */
256290075Sobrien  get_exception_pointer (cfun);
256390075Sobrien  get_exception_filter (cfun);
256450397Sobrien
256590075Sobrien  /* Construct the landing pads.  */
256650397Sobrien
256790075Sobrien  assign_filter_values ();
256890075Sobrien  build_post_landing_pads ();
256990075Sobrien  connect_post_landing_pads ();
257090075Sobrien  if (USING_SJLJ_EXCEPTIONS)
257190075Sobrien    sjlj_build_landing_pads ();
257290075Sobrien  else
257390075Sobrien    dw2_build_landing_pads ();
257450397Sobrien
257590075Sobrien  cfun->eh->built_landing_pads = 1;
257650397Sobrien
257790075Sobrien  /* We've totally changed the CFG.  Start over.  */
257890075Sobrien  find_exception_handler_labels ();
257990075Sobrien  rebuild_jump_labels (get_insns ());
258090075Sobrien  find_basic_blocks (get_insns (), max_reg_num (), 0);
258190075Sobrien  cleanup_cfg (CLEANUP_PRE_LOOP);
258290075Sobrien}
258390075Sobrien
258496263Sobrienstatic hashval_t
258596263Sobrienehl_hash (pentry)
258696263Sobrien     const PTR pentry;
258796263Sobrien{
258896263Sobrien  struct ehl_map_entry *entry = (struct ehl_map_entry *) pentry;
258996263Sobrien
259096263Sobrien  /* 2^32 * ((sqrt(5) - 1) / 2) */
259196263Sobrien  const hashval_t scaled_golden_ratio = 0x9e3779b9;
259296263Sobrien  return CODE_LABEL_NUMBER (entry->label) * scaled_golden_ratio;
259396263Sobrien}
259496263Sobrien
259596263Sobrienstatic int
259696263Sobrienehl_eq (pentry, pdata)
259796263Sobrien     const PTR pentry;
259896263Sobrien     const PTR pdata;
259996263Sobrien{
260096263Sobrien  struct ehl_map_entry *entry = (struct ehl_map_entry *) pentry;
260196263Sobrien  struct ehl_map_entry *data = (struct ehl_map_entry *) pdata;
260296263Sobrien
260396263Sobrien  return entry->label == data->label;
260496263Sobrien}
260596263Sobrien
260690075Sobrien/* This section handles removing dead code for flow.  */
260752284Sobrien
260896263Sobrien/* Remove LABEL from exception_handler_label_map.  */
260950397Sobrien
261090075Sobrienstatic void
261190075Sobrienremove_exception_handler_label (label)
261290075Sobrien     rtx label;
261390075Sobrien{
261496263Sobrien  struct ehl_map_entry **slot, tmp;
261550397Sobrien
261696263Sobrien  /* If exception_handler_label_map was not built yet,
261790075Sobrien     there is nothing to do.  */
261896263Sobrien  if (exception_handler_label_map == NULL)
261990075Sobrien    return;
262050397Sobrien
262196263Sobrien  tmp.label = label;
262296263Sobrien  slot = (struct ehl_map_entry **)
262396263Sobrien    htab_find_slot (exception_handler_label_map, &tmp, NO_INSERT);
262496263Sobrien  if (! slot)
262596263Sobrien    abort ();
262650397Sobrien
262796263Sobrien  htab_clear_slot (exception_handler_label_map, (void **) slot);
262850397Sobrien}
262950397Sobrien
263090075Sobrien/* Splice REGION from the region tree etc.  */
263150397Sobrien
263290075Sobrienstatic void
263390075Sobrienremove_eh_handler (region)
263490075Sobrien     struct eh_region *region;
263550397Sobrien{
263696263Sobrien  struct eh_region **pp, **pp_start, *p, *outer, *inner;
263790075Sobrien  rtx lab;
263850397Sobrien
263990075Sobrien  /* For the benefit of efficiently handling REG_EH_REGION notes,
264090075Sobrien     replace this region in the region array with its containing
264190075Sobrien     region.  Note that previous region deletions may result in
264296263Sobrien     multiple copies of this region in the array, so we have a
264396263Sobrien     list of alternate numbers by which we are known.  */
264450397Sobrien
264596263Sobrien  outer = region->outer;
264696263Sobrien  cfun->eh->region_array[region->region_number] = outer;
264796263Sobrien  if (region->aka)
264896263Sobrien    {
264996263Sobrien      int i;
265096263Sobrien      EXECUTE_IF_SET_IN_BITMAP (region->aka, 0, i,
265196263Sobrien	{ cfun->eh->region_array[i] = outer; });
265296263Sobrien    }
265396263Sobrien
265496263Sobrien  if (outer)
265596263Sobrien    {
265696263Sobrien      if (!outer->aka)
265796263Sobrien        outer->aka = BITMAP_XMALLOC ();
265896263Sobrien      if (region->aka)
265996263Sobrien	bitmap_a_or_b (outer->aka, outer->aka, region->aka);
266096263Sobrien      bitmap_set_bit (outer->aka, region->region_number);
266196263Sobrien    }
266296263Sobrien
266390075Sobrien  if (cfun->eh->built_landing_pads)
266490075Sobrien    lab = region->landing_pad;
266590075Sobrien  else
266690075Sobrien    lab = region->label;
266790075Sobrien  if (lab)
266890075Sobrien    remove_exception_handler_label (lab);
266950397Sobrien
267096263Sobrien  if (outer)
267196263Sobrien    pp_start = &outer->inner;
267290075Sobrien  else
267396263Sobrien    pp_start = &cfun->eh->region_tree;
267496263Sobrien  for (pp = pp_start, p = *pp; p != region; pp = &p->next_peer, p = *pp)
267590075Sobrien    continue;
267696263Sobrien  *pp = region->next_peer;
267750397Sobrien
267896263Sobrien  inner = region->inner;
267996263Sobrien  if (inner)
268090075Sobrien    {
268196263Sobrien      for (p = inner; p->next_peer ; p = p->next_peer)
268296263Sobrien	p->outer = outer;
268396263Sobrien      p->outer = outer;
268496263Sobrien
268596263Sobrien      p->next_peer = *pp_start;
268696263Sobrien      *pp_start = inner;
268790075Sobrien    }
268850397Sobrien
268990075Sobrien  if (region->type == ERT_CATCH)
269090075Sobrien    {
269190075Sobrien      struct eh_region *try, *next, *prev;
269252284Sobrien
269390075Sobrien      for (try = region->next_peer;
269490075Sobrien	   try->type == ERT_CATCH;
269590075Sobrien	   try = try->next_peer)
269690075Sobrien	continue;
269790075Sobrien      if (try->type != ERT_TRY)
269890075Sobrien	abort ();
269990075Sobrien
270090075Sobrien      next = region->u.catch.next_catch;
270190075Sobrien      prev = region->u.catch.prev_catch;
270290075Sobrien
270390075Sobrien      if (next)
270490075Sobrien	next->u.catch.prev_catch = prev;
270590075Sobrien      else
270690075Sobrien	try->u.try.last_catch = prev;
270790075Sobrien      if (prev)
270890075Sobrien	prev->u.catch.next_catch = next;
270990075Sobrien      else
271090075Sobrien	{
271190075Sobrien	  try->u.try.catch = next;
271290075Sobrien	  if (! next)
271390075Sobrien	    remove_eh_handler (try);
271490075Sobrien	}
271590075Sobrien    }
271690075Sobrien
271796263Sobrien  free_region (region);
271850397Sobrien}
271950397Sobrien
272090075Sobrien/* LABEL heads a basic block that is about to be deleted.  If this
272190075Sobrien   label corresponds to an exception region, we may be able to
272290075Sobrien   delete the region.  */
272350397Sobrien
272450397Sobrienvoid
272590075Sobrienmaybe_remove_eh_handler (label)
272690075Sobrien     rtx label;
272750397Sobrien{
272896263Sobrien  struct ehl_map_entry **slot, tmp;
272996263Sobrien  struct eh_region *region;
273050397Sobrien
273190075Sobrien  /* ??? After generating landing pads, it's not so simple to determine
273290075Sobrien     if the region data is completely unused.  One must examine the
273390075Sobrien     landing pad and the post landing pad, and whether an inner try block
273490075Sobrien     is referencing the catch handlers directly.  */
273590075Sobrien  if (cfun->eh->built_landing_pads)
273650397Sobrien    return;
273750397Sobrien
273896263Sobrien  tmp.label = label;
273996263Sobrien  slot = (struct ehl_map_entry **)
274096263Sobrien    htab_find_slot (exception_handler_label_map, &tmp, NO_INSERT);
274196263Sobrien  if (! slot)
274296263Sobrien    return;
274396263Sobrien  region = (*slot)->region;
274496263Sobrien  if (! region)
274596263Sobrien    return;
274696263Sobrien
274796263Sobrien  /* Flow will want to remove MUST_NOT_THROW regions as unreachable
274896263Sobrien     because there is no path to the fallback call to terminate.
274996263Sobrien     But the region continues to affect call-site data until there
275096263Sobrien     are no more contained calls, which we don't see here.  */
275196263Sobrien  if (region->type == ERT_MUST_NOT_THROW)
275250397Sobrien    {
275396263Sobrien      htab_clear_slot (exception_handler_label_map, (void **) slot);
275496263Sobrien      region->label = NULL_RTX;
275550397Sobrien    }
275696263Sobrien  else
275796263Sobrien    remove_eh_handler (region);
275850397Sobrien}
275950397Sobrien
276096263Sobrien/* Invokes CALLBACK for every exception handler label.  Only used by old
276196263Sobrien   loop hackery; should not be used by new code.  */
276296263Sobrien
276396263Sobrienvoid
276496263Sobrienfor_each_eh_label (callback)
276596263Sobrien     void (*callback) PARAMS ((rtx));
276696263Sobrien{
276796263Sobrien  htab_traverse (exception_handler_label_map, for_each_eh_label_1,
276896263Sobrien		 (void *)callback);
276996263Sobrien}
277096263Sobrien
277196263Sobrienstatic int
277296263Sobrienfor_each_eh_label_1 (pentry, data)
277396263Sobrien     PTR *pentry;
277496263Sobrien     PTR data;
277596263Sobrien{
277696263Sobrien  struct ehl_map_entry *entry = *(struct ehl_map_entry **)pentry;
277796263Sobrien  void (*callback) PARAMS ((rtx)) = (void (*) PARAMS ((rtx))) data;
277896263Sobrien
277996263Sobrien  (*callback) (entry->label);
278096263Sobrien  return 1;
278196263Sobrien}
278290075Sobrien
278390075Sobrien/* This section describes CFG exception edges for flow.  */
278450397Sobrien
278590075Sobrien/* For communicating between calls to reachable_next_level.  */
278690075Sobrienstruct reachable_info
278750397Sobrien{
278890075Sobrien  tree types_caught;
278990075Sobrien  tree types_allowed;
279090075Sobrien  rtx handlers;
279190075Sobrien};
279290075Sobrien
279390075Sobrien/* A subroutine of reachable_next_level.  Return true if TYPE, or a
279490075Sobrien   base class of TYPE, is in HANDLED.  */
279590075Sobrien
279690075Sobrienstatic int
279790075Sobriencheck_handled (handled, type)
279890075Sobrien     tree handled, type;
279990075Sobrien{
280090075Sobrien  tree t;
280190075Sobrien
280290075Sobrien  /* We can check for exact matches without front-end help.  */
280390075Sobrien  if (! lang_eh_type_covers)
280490075Sobrien    {
280590075Sobrien      for (t = handled; t ; t = TREE_CHAIN (t))
280690075Sobrien	if (TREE_VALUE (t) == type)
280790075Sobrien	  return 1;
280890075Sobrien    }
280990075Sobrien  else
281090075Sobrien    {
281190075Sobrien      for (t = handled; t ; t = TREE_CHAIN (t))
281290075Sobrien	if ((*lang_eh_type_covers) (TREE_VALUE (t), type))
281390075Sobrien	  return 1;
281490075Sobrien    }
281590075Sobrien
281650397Sobrien  return 0;
281750397Sobrien}
281850397Sobrien
281990075Sobrien/* A subroutine of reachable_next_level.  If we are collecting a list
282090075Sobrien   of handlers, add one.  After landing pad generation, reference
282190075Sobrien   it instead of the handlers themselves.  Further, the handlers are
282290075Sobrien   all wired together, so by referencing one, we've got them all.
282390075Sobrien   Before landing pad generation we reference each handler individually.
282450397Sobrien
282590075Sobrien   LP_REGION contains the landing pad; REGION is the handler.  */
282650397Sobrien
282790075Sobrienstatic void
282890075Sobrienadd_reachable_handler (info, lp_region, region)
282990075Sobrien     struct reachable_info *info;
283090075Sobrien     struct eh_region *lp_region;
283190075Sobrien     struct eh_region *region;
283250397Sobrien{
283390075Sobrien  if (! info)
283450397Sobrien    return;
283550397Sobrien
283690075Sobrien  if (cfun->eh->built_landing_pads)
283750397Sobrien    {
283890075Sobrien      if (! info->handlers)
283990075Sobrien	info->handlers = alloc_INSN_LIST (lp_region->landing_pad, NULL_RTX);
284050397Sobrien    }
284190075Sobrien  else
284290075Sobrien    info->handlers = alloc_INSN_LIST (region->label, info->handlers);
284350397Sobrien}
284450397Sobrien
284590075Sobrien/* Process one level of exception regions for reachability.
284690075Sobrien   If TYPE_THROWN is non-null, then it is the *exact* type being
284790075Sobrien   propagated.  If INFO is non-null, then collect handler labels
284890075Sobrien   and caught/allowed type information between invocations.  */
284950397Sobrien
285090075Sobrienstatic enum reachable_code
285190075Sobrienreachable_next_level (region, type_thrown, info)
285290075Sobrien     struct eh_region *region;
285390075Sobrien     tree type_thrown;
285490075Sobrien     struct reachable_info *info;
285550397Sobrien{
285690075Sobrien  switch (region->type)
285790075Sobrien    {
285890075Sobrien    case ERT_CLEANUP:
285990075Sobrien      /* Before landing-pad generation, we model control flow
286090075Sobrien	 directly to the individual handlers.  In this way we can
286190075Sobrien	 see that catch handler types may shadow one another.  */
286290075Sobrien      add_reachable_handler (info, region, region);
286390075Sobrien      return RNL_MAYBE_CAUGHT;
286450397Sobrien
286590075Sobrien    case ERT_TRY:
286690075Sobrien      {
286790075Sobrien	struct eh_region *c;
286890075Sobrien	enum reachable_code ret = RNL_NOT_CAUGHT;
286950397Sobrien
287090075Sobrien	for (c = region->u.try.catch; c ; c = c->u.catch.next_catch)
287190075Sobrien	  {
287290075Sobrien	    /* A catch-all handler ends the search.  */
287390075Sobrien	    /* ??? _Unwind_ForcedUnwind will want outer cleanups
287490075Sobrien	       to be run as well.  */
287590075Sobrien	    if (c->u.catch.type_list == NULL)
287690075Sobrien	      {
287790075Sobrien		add_reachable_handler (info, region, c);
287890075Sobrien		return RNL_CAUGHT;
287990075Sobrien	      }
288050397Sobrien
288190075Sobrien	    if (type_thrown)
288290075Sobrien	      {
288390075Sobrien		/* If we have at least one type match, end the search.  */
288490075Sobrien		tree tp_node = c->u.catch.type_list;
288550397Sobrien
288690075Sobrien		for (; tp_node; tp_node = TREE_CHAIN (tp_node))
288790075Sobrien		  {
288890075Sobrien		    tree type = TREE_VALUE (tp_node);
288950397Sobrien
289090075Sobrien		    if (type == type_thrown
289190075Sobrien			|| (lang_eh_type_covers
289290075Sobrien			    && (*lang_eh_type_covers) (type, type_thrown)))
289390075Sobrien		      {
289490075Sobrien			add_reachable_handler (info, region, c);
289590075Sobrien			return RNL_CAUGHT;
289690075Sobrien		      }
289790075Sobrien		  }
289850397Sobrien
289990075Sobrien		/* If we have definitive information of a match failure,
290090075Sobrien		   the catch won't trigger.  */
290190075Sobrien		if (lang_eh_type_covers)
290290075Sobrien		  return RNL_NOT_CAUGHT;
290390075Sobrien	      }
290450397Sobrien
290590075Sobrien	    /* At this point, we either don't know what type is thrown or
290690075Sobrien	       don't have front-end assistance to help deciding if it is
290790075Sobrien	       covered by one of the types in the list for this region.
290850397Sobrien
290990075Sobrien	       We'd then like to add this region to the list of reachable
291090075Sobrien	       handlers since it is indeed potentially reachable based on the
291190075Sobrien	       information we have.
291250397Sobrien
291390075Sobrien	       Actually, this handler is for sure not reachable if all the
291490075Sobrien	       types it matches have already been caught. That is, it is only
291590075Sobrien	       potentially reachable if at least one of the types it catches
291690075Sobrien	       has not been previously caught.  */
291750397Sobrien
291890075Sobrien	    if (! info)
291990075Sobrien	      ret = RNL_MAYBE_CAUGHT;
292090075Sobrien	    else
292190075Sobrien	      {
292290075Sobrien		tree tp_node = c->u.catch.type_list;
292390075Sobrien		bool maybe_reachable = false;
292450397Sobrien
292590075Sobrien		/* Compute the potential reachability of this handler and
292690075Sobrien		   update the list of types caught at the same time.  */
292790075Sobrien		for (; tp_node; tp_node = TREE_CHAIN (tp_node))
292890075Sobrien		  {
292990075Sobrien		    tree type = TREE_VALUE (tp_node);
293090075Sobrien
293190075Sobrien		    if (! check_handled (info->types_caught, type))
293290075Sobrien		      {
293390075Sobrien			info->types_caught
293490075Sobrien			  = tree_cons (NULL, type, info->types_caught);
293590075Sobrien
293690075Sobrien			maybe_reachable = true;
293790075Sobrien		      }
293890075Sobrien		  }
293990075Sobrien
294090075Sobrien		if (maybe_reachable)
294190075Sobrien		  {
294290075Sobrien		    add_reachable_handler (info, region, c);
294390075Sobrien
294490075Sobrien		    /* ??? If the catch type is a base class of every allowed
294590075Sobrien		       type, then we know we can stop the search.  */
294690075Sobrien		    ret = RNL_MAYBE_CAUGHT;
294790075Sobrien		  }
294890075Sobrien	      }
294990075Sobrien	  }
295090075Sobrien
295190075Sobrien	return ret;
295290075Sobrien      }
295390075Sobrien
295490075Sobrien    case ERT_ALLOWED_EXCEPTIONS:
295590075Sobrien      /* An empty list of types definitely ends the search.  */
295690075Sobrien      if (region->u.allowed.type_list == NULL_TREE)
295790075Sobrien	{
295890075Sobrien	  add_reachable_handler (info, region, region);
295990075Sobrien	  return RNL_CAUGHT;
296090075Sobrien	}
296190075Sobrien
296290075Sobrien      /* Collect a list of lists of allowed types for use in detecting
296390075Sobrien	 when a catch may be transformed into a catch-all.  */
296490075Sobrien      if (info)
296590075Sobrien	info->types_allowed = tree_cons (NULL_TREE,
296690075Sobrien					 region->u.allowed.type_list,
296790075Sobrien					 info->types_allowed);
296890075Sobrien
296990075Sobrien      /* If we have definitive information about the type hierarchy,
297090075Sobrien	 then we can tell if the thrown type will pass through the
297190075Sobrien	 filter.  */
297290075Sobrien      if (type_thrown && lang_eh_type_covers)
297390075Sobrien	{
297490075Sobrien	  if (check_handled (region->u.allowed.type_list, type_thrown))
297590075Sobrien	    return RNL_NOT_CAUGHT;
297690075Sobrien	  else
297790075Sobrien	    {
297890075Sobrien	      add_reachable_handler (info, region, region);
297990075Sobrien	      return RNL_CAUGHT;
298090075Sobrien	    }
298190075Sobrien	}
298290075Sobrien
298390075Sobrien      add_reachable_handler (info, region, region);
298490075Sobrien      return RNL_MAYBE_CAUGHT;
298590075Sobrien
298690075Sobrien    case ERT_CATCH:
298790075Sobrien      /* Catch regions are handled by their controling try region.  */
298890075Sobrien      return RNL_NOT_CAUGHT;
298990075Sobrien
299090075Sobrien    case ERT_MUST_NOT_THROW:
299190075Sobrien      /* Here we end our search, since no exceptions may propagate.
299290075Sobrien	 If we've touched down at some landing pad previous, then the
299390075Sobrien	 explicit function call we generated may be used.  Otherwise
299490075Sobrien	 the call is made by the runtime.  */
299590075Sobrien      if (info && info->handlers)
299690075Sobrien	{
299790075Sobrien	  add_reachable_handler (info, region, region);
299890075Sobrien          return RNL_CAUGHT;
299990075Sobrien	}
300090075Sobrien      else
300190075Sobrien	return RNL_BLOCKED;
300290075Sobrien
300390075Sobrien    case ERT_THROW:
300490075Sobrien    case ERT_FIXUP:
300590075Sobrien    case ERT_UNKNOWN:
300690075Sobrien      /* Shouldn't see these here.  */
300790075Sobrien      break;
300890075Sobrien    }
300990075Sobrien
301090075Sobrien  abort ();
301150397Sobrien}
301250397Sobrien
301390075Sobrien/* Retrieve a list of labels of exception handlers which can be
301490075Sobrien   reached by a given insn.  */
301550397Sobrien
301690075Sobrienrtx
301790075Sobrienreachable_handlers (insn)
301850397Sobrien     rtx insn;
301950397Sobrien{
302090075Sobrien  struct reachable_info info;
302190075Sobrien  struct eh_region *region;
302290075Sobrien  tree type_thrown;
302390075Sobrien  int region_number;
302450397Sobrien
302590075Sobrien  if (GET_CODE (insn) == JUMP_INSN
302690075Sobrien      && GET_CODE (PATTERN (insn)) == RESX)
302790075Sobrien    region_number = XINT (PATTERN (insn), 0);
302890075Sobrien  else
302950397Sobrien    {
303090075Sobrien      rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
303190075Sobrien      if (!note || INTVAL (XEXP (note, 0)) <= 0)
303290075Sobrien	return NULL;
303390075Sobrien      region_number = INTVAL (XEXP (note, 0));
303450397Sobrien    }
303550397Sobrien
303690075Sobrien  memset (&info, 0, sizeof (info));
303750397Sobrien
303890075Sobrien  region = cfun->eh->region_array[region_number];
303950397Sobrien
304090075Sobrien  type_thrown = NULL_TREE;
304190075Sobrien  if (GET_CODE (insn) == JUMP_INSN
304290075Sobrien      && GET_CODE (PATTERN (insn)) == RESX)
304390075Sobrien    {
304490075Sobrien      /* A RESX leaves a region instead of entering it.  Thus the
304590075Sobrien	 region itself may have been deleted out from under us.  */
304690075Sobrien      if (region == NULL)
304790075Sobrien	return NULL;
304890075Sobrien      region = region->outer;
304990075Sobrien    }
305090075Sobrien  else if (region->type == ERT_THROW)
305190075Sobrien    {
305290075Sobrien      type_thrown = region->u.throw.type;
305390075Sobrien      region = region->outer;
305490075Sobrien    }
305550397Sobrien
305690075Sobrien  for (; region; region = region->outer)
305790075Sobrien    if (reachable_next_level (region, type_thrown, &info) >= RNL_CAUGHT)
305890075Sobrien      break;
305950397Sobrien
306090075Sobrien  return info.handlers;
306190075Sobrien}
306250397Sobrien
306390075Sobrien/* Determine if the given INSN can throw an exception that is caught
306490075Sobrien   within the function.  */
306590075Sobrien
306690075Sobrienbool
306790075Sobriencan_throw_internal (insn)
306850397Sobrien     rtx insn;
306950397Sobrien{
307090075Sobrien  struct eh_region *region;
307190075Sobrien  tree type_thrown;
307290075Sobrien  rtx note;
307350397Sobrien
307490075Sobrien  if (! INSN_P (insn))
307590075Sobrien    return false;
307650397Sobrien
307790075Sobrien  if (GET_CODE (insn) == INSN
307890075Sobrien      && GET_CODE (PATTERN (insn)) == SEQUENCE)
307990075Sobrien    insn = XVECEXP (PATTERN (insn), 0, 0);
308052284Sobrien
308190075Sobrien  if (GET_CODE (insn) == CALL_INSN
308290075Sobrien      && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
308350397Sobrien    {
308490075Sobrien      int i;
308590075Sobrien      for (i = 0; i < 3; ++i)
308650397Sobrien	{
308790075Sobrien	  rtx sub = XEXP (PATTERN (insn), i);
308890075Sobrien	  for (; sub ; sub = NEXT_INSN (sub))
308990075Sobrien	    if (can_throw_internal (sub))
309090075Sobrien	      return true;
309150397Sobrien	}
309290075Sobrien      return false;
309390075Sobrien    }
309450397Sobrien
309590075Sobrien  /* Every insn that might throw has an EH_REGION note.  */
309690075Sobrien  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
309790075Sobrien  if (!note || INTVAL (XEXP (note, 0)) <= 0)
309890075Sobrien    return false;
309950397Sobrien
310090075Sobrien  region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
310190075Sobrien
310290075Sobrien  type_thrown = NULL_TREE;
310390075Sobrien  if (region->type == ERT_THROW)
310490075Sobrien    {
310590075Sobrien      type_thrown = region->u.throw.type;
310690075Sobrien      region = region->outer;
310750397Sobrien    }
310850397Sobrien
310990075Sobrien  /* If this exception is ignored by each and every containing region,
311090075Sobrien     then control passes straight out.  The runtime may handle some
311190075Sobrien     regions, which also do not require processing internally.  */
311290075Sobrien  for (; region; region = region->outer)
311350397Sobrien    {
311490075Sobrien      enum reachable_code how = reachable_next_level (region, type_thrown, 0);
311590075Sobrien      if (how == RNL_BLOCKED)
311690075Sobrien	return false;
311790075Sobrien      if (how != RNL_NOT_CAUGHT)
311890075Sobrien        return true;
311990075Sobrien    }
312050397Sobrien
312190075Sobrien  return false;
312290075Sobrien}
312350397Sobrien
312490075Sobrien/* Determine if the given INSN can throw an exception that is
312590075Sobrien   visible outside the function.  */
312650397Sobrien
312790075Sobrienbool
312890075Sobriencan_throw_external (insn)
312990075Sobrien     rtx insn;
313090075Sobrien{
313190075Sobrien  struct eh_region *region;
313290075Sobrien  tree type_thrown;
313390075Sobrien  rtx note;
313450397Sobrien
313590075Sobrien  if (! INSN_P (insn))
313690075Sobrien    return false;
313790075Sobrien
313890075Sobrien  if (GET_CODE (insn) == INSN
313990075Sobrien      && GET_CODE (PATTERN (insn)) == SEQUENCE)
314090075Sobrien    insn = XVECEXP (PATTERN (insn), 0, 0);
314190075Sobrien
314290075Sobrien  if (GET_CODE (insn) == CALL_INSN
314390075Sobrien      && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
314490075Sobrien    {
314590075Sobrien      int i;
314690075Sobrien      for (i = 0; i < 3; ++i)
314790075Sobrien	{
314890075Sobrien	  rtx sub = XEXP (PATTERN (insn), i);
314990075Sobrien	  for (; sub ; sub = NEXT_INSN (sub))
315090075Sobrien	    if (can_throw_external (sub))
315190075Sobrien	      return true;
315250397Sobrien	}
315390075Sobrien      return false;
315450397Sobrien    }
315590075Sobrien
315690075Sobrien  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
315790075Sobrien  if (!note)
315890075Sobrien    {
315990075Sobrien      /* Calls (and trapping insns) without notes are outside any
316090075Sobrien	 exception handling region in this function.  We have to
316190075Sobrien	 assume it might throw.  Given that the front end and middle
316290075Sobrien	 ends mark known NOTHROW functions, this isn't so wildly
316390075Sobrien	 inaccurate.  */
316490075Sobrien      return (GET_CODE (insn) == CALL_INSN
316590075Sobrien	      || (flag_non_call_exceptions
316690075Sobrien		  && may_trap_p (PATTERN (insn))));
316790075Sobrien    }
316890075Sobrien  if (INTVAL (XEXP (note, 0)) <= 0)
316990075Sobrien    return false;
317090075Sobrien
317190075Sobrien  region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
317290075Sobrien
317390075Sobrien  type_thrown = NULL_TREE;
317490075Sobrien  if (region->type == ERT_THROW)
317590075Sobrien    {
317690075Sobrien      type_thrown = region->u.throw.type;
317790075Sobrien      region = region->outer;
317890075Sobrien    }
317990075Sobrien
318090075Sobrien  /* If the exception is caught or blocked by any containing region,
318190075Sobrien     then it is not seen by any calling function.  */
318290075Sobrien  for (; region ; region = region->outer)
318390075Sobrien    if (reachable_next_level (region, type_thrown, NULL) >= RNL_CAUGHT)
318490075Sobrien      return false;
318590075Sobrien
318690075Sobrien  return true;
318750397Sobrien}
318850397Sobrien
318990075Sobrien/* True if nothing in this function can throw outside this function.  */
319050397Sobrien
319190075Sobrienbool
319290075Sobriennothrow_function_p ()
319350397Sobrien{
319450397Sobrien  rtx insn;
319550397Sobrien
319690075Sobrien  if (! flag_exceptions)
319790075Sobrien    return true;
319890075Sobrien
319950397Sobrien  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
320090075Sobrien    if (can_throw_external (insn))
320190075Sobrien      return false;
320290075Sobrien  for (insn = current_function_epilogue_delay_list; insn;
320390075Sobrien       insn = XEXP (insn, 1))
320490075Sobrien    if (can_throw_external (insn))
320590075Sobrien      return false;
320690075Sobrien
320790075Sobrien  return true;
320850397Sobrien}
320990075Sobrien
321050397Sobrien
321190075Sobrien/* Various hooks for unwind library.  */
321250397Sobrien
321350397Sobrien/* Do any necessary initialization to access arbitrary stack frames.
321450397Sobrien   On the SPARC, this means flushing the register windows.  */
321550397Sobrien
321650397Sobrienvoid
321750397Sobrienexpand_builtin_unwind_init ()
321850397Sobrien{
321950397Sobrien  /* Set this so all the registers get saved in our frame; we need to be
322090075Sobrien     able to copy the saved values for any registers from frames we unwind.  */
322150397Sobrien  current_function_has_nonlocal_label = 1;
322250397Sobrien
322350397Sobrien#ifdef SETUP_FRAME_ADDRESSES
322450397Sobrien  SETUP_FRAME_ADDRESSES ();
322550397Sobrien#endif
322650397Sobrien}
322750397Sobrien
322890075Sobrienrtx
322990075Sobrienexpand_builtin_eh_return_data_regno (arglist)
323090075Sobrien     tree arglist;
323190075Sobrien{
323290075Sobrien  tree which = TREE_VALUE (arglist);
323390075Sobrien  unsigned HOST_WIDE_INT iwhich;
323490075Sobrien
323590075Sobrien  if (TREE_CODE (which) != INTEGER_CST)
323690075Sobrien    {
323790075Sobrien      error ("argument of `__builtin_eh_return_regno' must be constant");
323890075Sobrien      return constm1_rtx;
323990075Sobrien    }
324090075Sobrien
324190075Sobrien  iwhich = tree_low_cst (which, 1);
324290075Sobrien  iwhich = EH_RETURN_DATA_REGNO (iwhich);
324390075Sobrien  if (iwhich == INVALID_REGNUM)
324490075Sobrien    return constm1_rtx;
324590075Sobrien
324690075Sobrien#ifdef DWARF_FRAME_REGNUM
324790075Sobrien  iwhich = DWARF_FRAME_REGNUM (iwhich);
324890075Sobrien#else
324990075Sobrien  iwhich = DBX_REGISTER_NUMBER (iwhich);
325090075Sobrien#endif
325190075Sobrien
325290075Sobrien  return GEN_INT (iwhich);
325390075Sobrien}
325490075Sobrien
325550397Sobrien/* Given a value extracted from the return address register or stack slot,
325650397Sobrien   return the actual address encoded in that value.  */
325750397Sobrien
325850397Sobrienrtx
325950397Sobrienexpand_builtin_extract_return_addr (addr_tree)
326050397Sobrien     tree addr_tree;
326150397Sobrien{
326250397Sobrien  rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
326390075Sobrien
326490075Sobrien  /* First mask out any unwanted bits.  */
326590075Sobrien#ifdef MASK_RETURN_ADDR
326696263Sobrien  expand_and (Pmode, addr, MASK_RETURN_ADDR, addr);
326790075Sobrien#endif
326890075Sobrien
326990075Sobrien  /* Then adjust to find the real return address.  */
327090075Sobrien#if defined (RETURN_ADDR_OFFSET)
327190075Sobrien  addr = plus_constant (addr, RETURN_ADDR_OFFSET);
327290075Sobrien#endif
327390075Sobrien
327490075Sobrien  return addr;
327550397Sobrien}
327650397Sobrien
327750397Sobrien/* Given an actual address in addr_tree, do any necessary encoding
327850397Sobrien   and return the value to be stored in the return address register or
327950397Sobrien   stack slot so the epilogue will return to that address.  */
328050397Sobrien
328150397Sobrienrtx
328250397Sobrienexpand_builtin_frob_return_addr (addr_tree)
328350397Sobrien     tree addr_tree;
328450397Sobrien{
328590075Sobrien  rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, 0);
328690075Sobrien
328790075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED
328890075Sobrien  if (GET_MODE (addr) != Pmode)
328990075Sobrien    addr = convert_memory_address (Pmode, addr);
329090075Sobrien#endif
329190075Sobrien
329250397Sobrien#ifdef RETURN_ADDR_OFFSET
329390075Sobrien  addr = force_reg (Pmode, addr);
329450397Sobrien  addr = plus_constant (addr, -RETURN_ADDR_OFFSET);
329550397Sobrien#endif
329690075Sobrien
329750397Sobrien  return addr;
329850397Sobrien}
329950397Sobrien
330090075Sobrien/* Set up the epilogue with the magic bits we'll need to return to the
330190075Sobrien   exception handler.  */
330250397Sobrien
330390075Sobrienvoid
330490075Sobrienexpand_builtin_eh_return (stackadj_tree, handler_tree)
330590075Sobrien    tree stackadj_tree, handler_tree;
330690075Sobrien{
330790075Sobrien  rtx stackadj, handler;
330850397Sobrien
330990075Sobrien  stackadj = expand_expr (stackadj_tree, cfun->eh->ehr_stackadj, VOIDmode, 0);
331090075Sobrien  handler = expand_expr (handler_tree, cfun->eh->ehr_handler, VOIDmode, 0);
331150397Sobrien
331290075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED
331390075Sobrien  if (GET_MODE (stackadj) != Pmode)
331490075Sobrien    stackadj = convert_memory_address (Pmode, stackadj);
331550397Sobrien
331690075Sobrien  if (GET_MODE (handler) != Pmode)
331790075Sobrien    handler = convert_memory_address (Pmode, handler);
331850397Sobrien#endif
331950397Sobrien
332090075Sobrien  if (! cfun->eh->ehr_label)
332190075Sobrien    {
332290075Sobrien      cfun->eh->ehr_stackadj = copy_to_reg (stackadj);
332390075Sobrien      cfun->eh->ehr_handler = copy_to_reg (handler);
332490075Sobrien      cfun->eh->ehr_label = gen_label_rtx ();
332590075Sobrien    }
332650397Sobrien  else
332790075Sobrien    {
332890075Sobrien      if (stackadj != cfun->eh->ehr_stackadj)
332990075Sobrien	emit_move_insn (cfun->eh->ehr_stackadj, stackadj);
333090075Sobrien      if (handler != cfun->eh->ehr_handler)
333190075Sobrien	emit_move_insn (cfun->eh->ehr_handler, handler);
333290075Sobrien    }
333350397Sobrien
333490075Sobrien  emit_jump (cfun->eh->ehr_label);
333590075Sobrien}
333690075Sobrien
333790075Sobrienvoid
333890075Sobrienexpand_eh_return ()
333990075Sobrien{
334090075Sobrien  rtx sa, ra, around_label;
334190075Sobrien
334290075Sobrien  if (! cfun->eh->ehr_label)
334390075Sobrien    return;
334490075Sobrien
334590075Sobrien  sa = EH_RETURN_STACKADJ_RTX;
334690075Sobrien  if (! sa)
334750397Sobrien    {
334890075Sobrien      error ("__builtin_eh_return not supported on this target");
334990075Sobrien      return;
335090075Sobrien    }
335150397Sobrien
335290075Sobrien  current_function_calls_eh_return = 1;
335390075Sobrien
335490075Sobrien  around_label = gen_label_rtx ();
335590075Sobrien  emit_move_insn (sa, const0_rtx);
335690075Sobrien  emit_jump (around_label);
335790075Sobrien
335890075Sobrien  emit_label (cfun->eh->ehr_label);
335990075Sobrien  clobber_return_register ();
336090075Sobrien
336190075Sobrien#ifdef HAVE_eh_return
336290075Sobrien  if (HAVE_eh_return)
336390075Sobrien    emit_insn (gen_eh_return (cfun->eh->ehr_stackadj, cfun->eh->ehr_handler));
336490075Sobrien  else
336590075Sobrien#endif
336690075Sobrien    {
336790075Sobrien      ra = EH_RETURN_HANDLER_RTX;
336890075Sobrien      if (! ra)
336990075Sobrien	{
337090075Sobrien	  error ("__builtin_eh_return not supported on this target");
337190075Sobrien	  ra = gen_reg_rtx (Pmode);
337290075Sobrien	}
337390075Sobrien
337490075Sobrien      emit_move_insn (sa, cfun->eh->ehr_stackadj);
337590075Sobrien      emit_move_insn (ra, cfun->eh->ehr_handler);
337650397Sobrien    }
337750397Sobrien
337890075Sobrien  emit_label (around_label);
337990075Sobrien}
338090075Sobrien
338190075Sobrien/* In the following functions, we represent entries in the action table
338290075Sobrien   as 1-based indices.  Special cases are:
338352284Sobrien
338490075Sobrien	 0:	null action record, non-null landing pad; implies cleanups
338590075Sobrien	-1:	null action record, null landing pad; implies no action
338690075Sobrien	-2:	no call-site entry; implies must_not_throw
338790075Sobrien	-3:	we have yet to process outer regions
338852284Sobrien
338990075Sobrien   Further, no special cases apply to the "next" field of the record.
339090075Sobrien   For next, 0 means end of list.  */
339190075Sobrien
339290075Sobrienstruct action_record
339390075Sobrien{
339490075Sobrien  int offset;
339590075Sobrien  int filter;
339690075Sobrien  int next;
339790075Sobrien};
339890075Sobrien
339990075Sobrienstatic int
340090075Sobrienaction_record_eq (pentry, pdata)
340190075Sobrien     const PTR pentry;
340290075Sobrien     const PTR pdata;
340390075Sobrien{
340490075Sobrien  const struct action_record *entry = (const struct action_record *) pentry;
340590075Sobrien  const struct action_record *data = (const struct action_record *) pdata;
340690075Sobrien  return entry->filter == data->filter && entry->next == data->next;
340750397Sobrien}
340850397Sobrien
340990075Sobrienstatic hashval_t
341090075Sobrienaction_record_hash (pentry)
341190075Sobrien     const PTR pentry;
341290075Sobrien{
341390075Sobrien  const struct action_record *entry = (const struct action_record *) pentry;
341490075Sobrien  return entry->next * 1009 + entry->filter;
341590075Sobrien}
341650397Sobrien
341790075Sobrienstatic int
341890075Sobrienadd_action_record (ar_hash, filter, next)
341990075Sobrien     htab_t ar_hash;
342090075Sobrien     int filter, next;
342150397Sobrien{
342290075Sobrien  struct action_record **slot, *new, tmp;
342390075Sobrien
342490075Sobrien  tmp.filter = filter;
342590075Sobrien  tmp.next = next;
342690075Sobrien  slot = (struct action_record **) htab_find_slot (ar_hash, &tmp, INSERT);
342790075Sobrien
342890075Sobrien  if ((new = *slot) == NULL)
342990075Sobrien    {
343090075Sobrien      new = (struct action_record *) xmalloc (sizeof (*new));
343190075Sobrien      new->offset = VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) + 1;
343290075Sobrien      new->filter = filter;
343390075Sobrien      new->next = next;
343490075Sobrien      *slot = new;
343590075Sobrien
343690075Sobrien      /* The filter value goes in untouched.  The link to the next
343790075Sobrien	 record is a "self-relative" byte offset, or zero to indicate
343890075Sobrien	 that there is no next record.  So convert the absolute 1 based
343990075Sobrien	 indices we've been carrying around into a displacement.  */
344090075Sobrien
344190075Sobrien      push_sleb128 (&cfun->eh->action_record_data, filter);
344290075Sobrien      if (next)
344390075Sobrien	next -= VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) + 1;
344490075Sobrien      push_sleb128 (&cfun->eh->action_record_data, next);
344590075Sobrien    }
344690075Sobrien
344790075Sobrien  return new->offset;
344850397Sobrien}
344950397Sobrien
345090075Sobrienstatic int
345190075Sobriencollect_one_action_chain (ar_hash, region)
345290075Sobrien     htab_t ar_hash;
345390075Sobrien     struct eh_region *region;
345490075Sobrien{
345590075Sobrien  struct eh_region *c;
345690075Sobrien  int next;
345750397Sobrien
345890075Sobrien  /* If we've reached the top of the region chain, then we have
345990075Sobrien     no actions, and require no landing pad.  */
346090075Sobrien  if (region == NULL)
346190075Sobrien    return -1;
346290075Sobrien
346390075Sobrien  switch (region->type)
346490075Sobrien    {
346590075Sobrien    case ERT_CLEANUP:
346690075Sobrien      /* A cleanup adds a zero filter to the beginning of the chain, but
346790075Sobrien	 there are special cases to look out for.  If there are *only*
346890075Sobrien	 cleanups along a path, then it compresses to a zero action.
346990075Sobrien	 Further, if there are multiple cleanups along a path, we only
347090075Sobrien	 need to represent one of them, as that is enough to trigger
347190075Sobrien	 entry to the landing pad at runtime.  */
347290075Sobrien      next = collect_one_action_chain (ar_hash, region->outer);
347390075Sobrien      if (next <= 0)
347490075Sobrien	return 0;
347590075Sobrien      for (c = region->outer; c ; c = c->outer)
347690075Sobrien	if (c->type == ERT_CLEANUP)
347790075Sobrien	  return next;
347890075Sobrien      return add_action_record (ar_hash, 0, next);
347990075Sobrien
348090075Sobrien    case ERT_TRY:
348190075Sobrien      /* Process the associated catch regions in reverse order.
348290075Sobrien	 If there's a catch-all handler, then we don't need to
348390075Sobrien	 search outer regions.  Use a magic -3 value to record
348490075Sobrien	 that we haven't done the outer search.  */
348590075Sobrien      next = -3;
348690075Sobrien      for (c = region->u.try.last_catch; c ; c = c->u.catch.prev_catch)
348790075Sobrien	{
348890075Sobrien	  if (c->u.catch.type_list == NULL)
348990075Sobrien	    {
349090075Sobrien	      /* Retrieve the filter from the head of the filter list
349190075Sobrien		 where we have stored it (see assign_filter_values).  */
349290075Sobrien	      int filter
349390075Sobrien		= TREE_INT_CST_LOW (TREE_VALUE (c->u.catch.filter_list));
349490075Sobrien
349590075Sobrien	      next = add_action_record (ar_hash, filter, 0);
349690075Sobrien	    }
349790075Sobrien	  else
349890075Sobrien	    {
349990075Sobrien	      /* Once the outer search is done, trigger an action record for
350090075Sobrien                 each filter we have.  */
350190075Sobrien	      tree flt_node;
350290075Sobrien
350390075Sobrien	      if (next == -3)
350490075Sobrien		{
350590075Sobrien		  next = collect_one_action_chain (ar_hash, region->outer);
350690075Sobrien
350790075Sobrien		  /* If there is no next action, terminate the chain.  */
350890075Sobrien		  if (next == -1)
350990075Sobrien		    next = 0;
351090075Sobrien		  /* If all outer actions are cleanups or must_not_throw,
351190075Sobrien		     we'll have no action record for it, since we had wanted
351290075Sobrien		     to encode these states in the call-site record directly.
351390075Sobrien		     Add a cleanup action to the chain to catch these.  */
351490075Sobrien		  else if (next <= 0)
351590075Sobrien		    next = add_action_record (ar_hash, 0, 0);
351690075Sobrien		}
351790075Sobrien
351890075Sobrien	      flt_node = c->u.catch.filter_list;
351990075Sobrien	      for (; flt_node; flt_node = TREE_CHAIN (flt_node))
352090075Sobrien		{
352190075Sobrien		  int filter = TREE_INT_CST_LOW (TREE_VALUE (flt_node));
352290075Sobrien		  next = add_action_record (ar_hash, filter, next);
352390075Sobrien		}
352490075Sobrien	    }
352590075Sobrien	}
352690075Sobrien      return next;
352790075Sobrien
352890075Sobrien    case ERT_ALLOWED_EXCEPTIONS:
352990075Sobrien      /* An exception specification adds its filter to the
353090075Sobrien	 beginning of the chain.  */
353190075Sobrien      next = collect_one_action_chain (ar_hash, region->outer);
353290075Sobrien      return add_action_record (ar_hash, region->u.allowed.filter,
353390075Sobrien				next < 0 ? 0 : next);
353490075Sobrien
353590075Sobrien    case ERT_MUST_NOT_THROW:
353690075Sobrien      /* A must-not-throw region with no inner handlers or cleanups
353790075Sobrien	 requires no call-site entry.  Note that this differs from
353890075Sobrien	 the no handler or cleanup case in that we do require an lsda
353990075Sobrien	 to be generated.  Return a magic -2 value to record this.  */
354090075Sobrien      return -2;
354190075Sobrien
354290075Sobrien    case ERT_CATCH:
354390075Sobrien    case ERT_THROW:
354490075Sobrien      /* CATCH regions are handled in TRY above.  THROW regions are
354590075Sobrien	 for optimization information only and produce no output.  */
354690075Sobrien      return collect_one_action_chain (ar_hash, region->outer);
354790075Sobrien
354890075Sobrien    default:
354990075Sobrien      abort ();
355090075Sobrien    }
355190075Sobrien}
355290075Sobrien
355390075Sobrienstatic int
355490075Sobrienadd_call_site (landing_pad, action)
355590075Sobrien     rtx landing_pad;
355690075Sobrien     int action;
355750397Sobrien{
355890075Sobrien  struct call_site_record *data = cfun->eh->call_site_data;
355990075Sobrien  int used = cfun->eh->call_site_data_used;
356090075Sobrien  int size = cfun->eh->call_site_data_size;
356150397Sobrien
356290075Sobrien  if (used >= size)
356390075Sobrien    {
356490075Sobrien      size = (size ? size * 2 : 64);
356590075Sobrien      data = (struct call_site_record *)
356690075Sobrien	xrealloc (data, sizeof (*data) * size);
356790075Sobrien      cfun->eh->call_site_data = data;
356890075Sobrien      cfun->eh->call_site_data_size = size;
356990075Sobrien    }
357090075Sobrien
357190075Sobrien  data[used].landing_pad = landing_pad;
357290075Sobrien  data[used].action = action;
357390075Sobrien
357490075Sobrien  cfun->eh->call_site_data_used = used + 1;
357590075Sobrien
357690075Sobrien  return used + call_site_base;
357750397Sobrien}
357850397Sobrien
357990075Sobrien/* Turn REG_EH_REGION notes back into NOTE_INSN_EH_REGION notes.
358090075Sobrien   The new note numbers will not refer to region numbers, but
358190075Sobrien   instead to call site entries.  */
358290075Sobrien
358352284Sobrienvoid
358490075Sobrienconvert_to_eh_region_ranges ()
358550397Sobrien{
358690075Sobrien  rtx insn, iter, note;
358790075Sobrien  htab_t ar_hash;
358890075Sobrien  int last_action = -3;
358990075Sobrien  rtx last_action_insn = NULL_RTX;
359090075Sobrien  rtx last_landing_pad = NULL_RTX;
359190075Sobrien  rtx first_no_action_insn = NULL_RTX;
359290075Sobrien  int call_site = 0;
359350397Sobrien
359490075Sobrien  if (USING_SJLJ_EXCEPTIONS || cfun->eh->region_tree == NULL)
359552284Sobrien    return;
359650397Sobrien
359790075Sobrien  VARRAY_UCHAR_INIT (cfun->eh->action_record_data, 64, "action_record_data");
359850397Sobrien
359990075Sobrien  ar_hash = htab_create (31, action_record_hash, action_record_eq, free);
360050397Sobrien
360190075Sobrien  for (iter = get_insns (); iter ; iter = NEXT_INSN (iter))
360290075Sobrien    if (INSN_P (iter))
360390075Sobrien      {
360490075Sobrien	struct eh_region *region;
360590075Sobrien	int this_action;
360690075Sobrien	rtx this_landing_pad;
360750397Sobrien
360890075Sobrien	insn = iter;
360990075Sobrien	if (GET_CODE (insn) == INSN
361090075Sobrien	    && GET_CODE (PATTERN (insn)) == SEQUENCE)
361190075Sobrien	  insn = XVECEXP (PATTERN (insn), 0, 0);
361250397Sobrien
361390075Sobrien	note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
361490075Sobrien	if (!note)
361590075Sobrien	  {
361690075Sobrien	    if (! (GET_CODE (insn) == CALL_INSN
361790075Sobrien		   || (flag_non_call_exceptions
361890075Sobrien		       && may_trap_p (PATTERN (insn)))))
361990075Sobrien	      continue;
362090075Sobrien	    this_action = -1;
362190075Sobrien	    region = NULL;
362290075Sobrien	  }
362390075Sobrien	else
362490075Sobrien	  {
362590075Sobrien	    if (INTVAL (XEXP (note, 0)) <= 0)
362690075Sobrien	      continue;
362790075Sobrien	    region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
362890075Sobrien	    this_action = collect_one_action_chain (ar_hash, region);
362990075Sobrien	  }
363050397Sobrien
363190075Sobrien	/* Existence of catch handlers, or must-not-throw regions
363290075Sobrien	   implies that an lsda is needed (even if empty).  */
363390075Sobrien	if (this_action != -1)
363490075Sobrien	  cfun->uses_eh_lsda = 1;
363550397Sobrien
363690075Sobrien	/* Delay creation of region notes for no-action regions
363790075Sobrien	   until we're sure that an lsda will be required.  */
363890075Sobrien	else if (last_action == -3)
363990075Sobrien	  {
364090075Sobrien	    first_no_action_insn = iter;
364190075Sobrien	    last_action = -1;
364290075Sobrien	  }
364350397Sobrien
364490075Sobrien	/* Cleanups and handlers may share action chains but not
364590075Sobrien	   landing pads.  Collect the landing pad for this region.  */
364690075Sobrien	if (this_action >= 0)
364790075Sobrien	  {
364890075Sobrien	    struct eh_region *o;
364990075Sobrien	    for (o = region; ! o->landing_pad ; o = o->outer)
365090075Sobrien	      continue;
365190075Sobrien	    this_landing_pad = o->landing_pad;
365290075Sobrien	  }
365390075Sobrien	else
365490075Sobrien	  this_landing_pad = NULL_RTX;
365550397Sobrien
365690075Sobrien	/* Differing actions or landing pads implies a change in call-site
365790075Sobrien	   info, which implies some EH_REGION note should be emitted.  */
365890075Sobrien	if (last_action != this_action
365990075Sobrien	    || last_landing_pad != this_landing_pad)
366090075Sobrien	  {
366190075Sobrien	    /* If we'd not seen a previous action (-3) or the previous
366290075Sobrien	       action was must-not-throw (-2), then we do not need an
366390075Sobrien	       end note.  */
366490075Sobrien	    if (last_action >= -1)
366590075Sobrien	      {
366690075Sobrien		/* If we delayed the creation of the begin, do it now.  */
366790075Sobrien		if (first_no_action_insn)
366890075Sobrien		  {
366990075Sobrien		    call_site = add_call_site (NULL_RTX, 0);
367090075Sobrien		    note = emit_note_before (NOTE_INSN_EH_REGION_BEG,
367190075Sobrien					     first_no_action_insn);
367290075Sobrien		    NOTE_EH_HANDLER (note) = call_site;
367390075Sobrien		    first_no_action_insn = NULL_RTX;
367490075Sobrien		  }
367550397Sobrien
367690075Sobrien		note = emit_note_after (NOTE_INSN_EH_REGION_END,
367790075Sobrien					last_action_insn);
367890075Sobrien		NOTE_EH_HANDLER (note) = call_site;
367990075Sobrien	      }
368052284Sobrien
368190075Sobrien	    /* If the new action is must-not-throw, then no region notes
368290075Sobrien	       are created.  */
368390075Sobrien	    if (this_action >= -1)
368490075Sobrien	      {
368590075Sobrien		call_site = add_call_site (this_landing_pad,
368690075Sobrien					   this_action < 0 ? 0 : this_action);
368790075Sobrien		note = emit_note_before (NOTE_INSN_EH_REGION_BEG, iter);
368890075Sobrien		NOTE_EH_HANDLER (note) = call_site;
368990075Sobrien	      }
369052284Sobrien
369190075Sobrien	    last_action = this_action;
369290075Sobrien	    last_landing_pad = this_landing_pad;
369390075Sobrien	  }
369490075Sobrien	last_action_insn = iter;
369590075Sobrien      }
369652284Sobrien
369790075Sobrien  if (last_action >= -1 && ! first_no_action_insn)
369890075Sobrien    {
369990075Sobrien      note = emit_note_after (NOTE_INSN_EH_REGION_END, last_action_insn);
370090075Sobrien      NOTE_EH_HANDLER (note) = call_site;
370190075Sobrien    }
370252284Sobrien
370390075Sobrien  htab_delete (ar_hash);
370450397Sobrien}
370590075Sobrien
370650397Sobrien
370790075Sobrienstatic void
370890075Sobrienpush_uleb128 (data_area, value)
370990075Sobrien     varray_type *data_area;
371090075Sobrien     unsigned int value;
371190075Sobrien{
371290075Sobrien  do
371390075Sobrien    {
371490075Sobrien      unsigned char byte = value & 0x7f;
371590075Sobrien      value >>= 7;
371690075Sobrien      if (value)
371790075Sobrien	byte |= 0x80;
371890075Sobrien      VARRAY_PUSH_UCHAR (*data_area, byte);
371990075Sobrien    }
372090075Sobrien  while (value);
372190075Sobrien}
372250397Sobrien
372390075Sobrienstatic void
372490075Sobrienpush_sleb128 (data_area, value)
372590075Sobrien     varray_type *data_area;
372690075Sobrien     int value;
372790075Sobrien{
372890075Sobrien  unsigned char byte;
372990075Sobrien  int more;
373050397Sobrien
373190075Sobrien  do
373290075Sobrien    {
373390075Sobrien      byte = value & 0x7f;
373490075Sobrien      value >>= 7;
373590075Sobrien      more = ! ((value == 0 && (byte & 0x40) == 0)
373690075Sobrien		|| (value == -1 && (byte & 0x40) != 0));
373790075Sobrien      if (more)
373890075Sobrien	byte |= 0x80;
373990075Sobrien      VARRAY_PUSH_UCHAR (*data_area, byte);
374090075Sobrien    }
374190075Sobrien  while (more);
374290075Sobrien}
374350397Sobrien
374490075Sobrien
374590075Sobrien#ifndef HAVE_AS_LEB128
374690075Sobrienstatic int
374790075Sobriendw2_size_of_call_site_table ()
374850397Sobrien{
374990075Sobrien  int n = cfun->eh->call_site_data_used;
375090075Sobrien  int size = n * (4 + 4 + 4);
375190075Sobrien  int i;
375250397Sobrien
375390075Sobrien  for (i = 0; i < n; ++i)
375450397Sobrien    {
375590075Sobrien      struct call_site_record *cs = &cfun->eh->call_site_data[i];
375690075Sobrien      size += size_of_uleb128 (cs->action);
375750397Sobrien    }
375890075Sobrien
375990075Sobrien  return size;
376050397Sobrien}
376150397Sobrien
376290075Sobrienstatic int
376390075Sobriensjlj_size_of_call_site_table ()
376490075Sobrien{
376590075Sobrien  int n = cfun->eh->call_site_data_used;
376690075Sobrien  int size = 0;
376790075Sobrien  int i;
376850397Sobrien
376990075Sobrien  for (i = 0; i < n; ++i)
377090075Sobrien    {
377190075Sobrien      struct call_site_record *cs = &cfun->eh->call_site_data[i];
377290075Sobrien      size += size_of_uleb128 (INTVAL (cs->landing_pad));
377390075Sobrien      size += size_of_uleb128 (cs->action);
377490075Sobrien    }
377590075Sobrien
377690075Sobrien  return size;
377790075Sobrien}
377890075Sobrien#endif
377990075Sobrien
378090075Sobrienstatic void
378190075Sobriendw2_output_call_site_table ()
378250397Sobrien{
378390075Sobrien  const char *const function_start_lab
378490075Sobrien    = IDENTIFIER_POINTER (current_function_func_begin_label);
378590075Sobrien  int n = cfun->eh->call_site_data_used;
378690075Sobrien  int i;
378750397Sobrien
378890075Sobrien  for (i = 0; i < n; ++i)
378950397Sobrien    {
379090075Sobrien      struct call_site_record *cs = &cfun->eh->call_site_data[i];
379190075Sobrien      char reg_start_lab[32];
379290075Sobrien      char reg_end_lab[32];
379390075Sobrien      char landing_pad_lab[32];
379490075Sobrien
379590075Sobrien      ASM_GENERATE_INTERNAL_LABEL (reg_start_lab, "LEHB", call_site_base + i);
379690075Sobrien      ASM_GENERATE_INTERNAL_LABEL (reg_end_lab, "LEHE", call_site_base + i);
379790075Sobrien
379890075Sobrien      if (cs->landing_pad)
379990075Sobrien	ASM_GENERATE_INTERNAL_LABEL (landing_pad_lab, "L",
380090075Sobrien				     CODE_LABEL_NUMBER (cs->landing_pad));
380190075Sobrien
380290075Sobrien      /* ??? Perhaps use insn length scaling if the assembler supports
380390075Sobrien	 generic arithmetic.  */
380490075Sobrien      /* ??? Perhaps use attr_length to choose data1 or data2 instead of
380590075Sobrien	 data4 if the function is small enough.  */
380690075Sobrien#ifdef HAVE_AS_LEB128
380790075Sobrien      dw2_asm_output_delta_uleb128 (reg_start_lab, function_start_lab,
380890075Sobrien				    "region %d start", i);
380990075Sobrien      dw2_asm_output_delta_uleb128 (reg_end_lab, reg_start_lab,
381090075Sobrien				    "length");
381190075Sobrien      if (cs->landing_pad)
381290075Sobrien	dw2_asm_output_delta_uleb128 (landing_pad_lab, function_start_lab,
381390075Sobrien				      "landing pad");
381490075Sobrien      else
381590075Sobrien	dw2_asm_output_data_uleb128 (0, "landing pad");
381690075Sobrien#else
381790075Sobrien      dw2_asm_output_delta (4, reg_start_lab, function_start_lab,
381890075Sobrien			    "region %d start", i);
381990075Sobrien      dw2_asm_output_delta (4, reg_end_lab, reg_start_lab, "length");
382090075Sobrien      if (cs->landing_pad)
382190075Sobrien	dw2_asm_output_delta (4, landing_pad_lab, function_start_lab,
382290075Sobrien			      "landing pad");
382390075Sobrien      else
382490075Sobrien	dw2_asm_output_data (4, 0, "landing pad");
382590075Sobrien#endif
382690075Sobrien      dw2_asm_output_data_uleb128 (cs->action, "action");
382750397Sobrien    }
382890075Sobrien
382990075Sobrien  call_site_base += n;
383050397Sobrien}
383150397Sobrien
383290075Sobrienstatic void
383390075Sobriensjlj_output_call_site_table ()
383490075Sobrien{
383590075Sobrien  int n = cfun->eh->call_site_data_used;
383690075Sobrien  int i;
383750397Sobrien
383890075Sobrien  for (i = 0; i < n; ++i)
383990075Sobrien    {
384090075Sobrien      struct call_site_record *cs = &cfun->eh->call_site_data[i];
384190075Sobrien
384290075Sobrien      dw2_asm_output_data_uleb128 (INTVAL (cs->landing_pad),
384390075Sobrien				   "region %d landing pad", i);
384490075Sobrien      dw2_asm_output_data_uleb128 (cs->action, "action");
384590075Sobrien    }
384690075Sobrien
384790075Sobrien  call_site_base += n;
384890075Sobrien}
384990075Sobrien
385090075Sobrienvoid
385190075Sobrienoutput_function_exception_table ()
385250397Sobrien{
385390075Sobrien  int tt_format, cs_format, lp_format, i, n;
385490075Sobrien#ifdef HAVE_AS_LEB128
385590075Sobrien  char ttype_label[32];
385690075Sobrien  char cs_after_size_label[32];
385790075Sobrien  char cs_end_label[32];
385890075Sobrien#else
385990075Sobrien  int call_site_len;
386090075Sobrien#endif
386190075Sobrien  int have_tt_data;
386290075Sobrien  int funcdef_number;
386390075Sobrien  int tt_format_size = 0;
386450397Sobrien
386590075Sobrien  /* Not all functions need anything.  */
386690075Sobrien  if (! cfun->uses_eh_lsda)
386750397Sobrien    return;
386850397Sobrien
386990075Sobrien  funcdef_number = (USING_SJLJ_EXCEPTIONS
387090075Sobrien		    ? sjlj_funcdef_number
387190075Sobrien		    : current_funcdef_number);
387250397Sobrien
387390075Sobrien#ifdef IA64_UNWIND_INFO
387490075Sobrien  fputs ("\t.personality\t", asm_out_file);
387590075Sobrien  output_addr_const (asm_out_file, eh_personality_libfunc);
387690075Sobrien  fputs ("\n\t.handlerdata\n", asm_out_file);
387790075Sobrien  /* Note that varasm still thinks we're in the function's code section.
387890075Sobrien     The ".endp" directive that will immediately follow will take us back.  */
387990075Sobrien#else
388090075Sobrien  (*targetm.asm_out.exception_section) ();
388190075Sobrien#endif
388250397Sobrien
388390075Sobrien  have_tt_data = (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) > 0
388490075Sobrien		  || VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) > 0);
388550397Sobrien
388690075Sobrien  /* Indicate the format of the @TType entries.  */
388790075Sobrien  if (! have_tt_data)
388890075Sobrien    tt_format = DW_EH_PE_omit;
388990075Sobrien  else
389090075Sobrien    {
389190075Sobrien      tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
389290075Sobrien#ifdef HAVE_AS_LEB128
389390075Sobrien      ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT", funcdef_number);
389490075Sobrien#endif
389590075Sobrien      tt_format_size = size_of_encoded_value (tt_format);
389650397Sobrien
389790075Sobrien      assemble_align (tt_format_size * BITS_PER_UNIT);
389890075Sobrien    }
389950397Sobrien
390090075Sobrien  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LLSDA", funcdef_number);
390150397Sobrien
390290075Sobrien  /* The LSDA header.  */
390350397Sobrien
390490075Sobrien  /* Indicate the format of the landing pad start pointer.  An omitted
390590075Sobrien     field implies @LPStart == @Start.  */
390690075Sobrien  /* Currently we always put @LPStart == @Start.  This field would
390790075Sobrien     be most useful in moving the landing pads completely out of
390890075Sobrien     line to another section, but it could also be used to minimize
390990075Sobrien     the size of uleb128 landing pad offsets.  */
391090075Sobrien  lp_format = DW_EH_PE_omit;
391190075Sobrien  dw2_asm_output_data (1, lp_format, "@LPStart format (%s)",
391290075Sobrien		       eh_data_format_name (lp_format));
391350397Sobrien
391490075Sobrien  /* @LPStart pointer would go here.  */
391550397Sobrien
391690075Sobrien  dw2_asm_output_data (1, tt_format, "@TType format (%s)",
391790075Sobrien		       eh_data_format_name (tt_format));
391850397Sobrien
391990075Sobrien#ifndef HAVE_AS_LEB128
392090075Sobrien  if (USING_SJLJ_EXCEPTIONS)
392190075Sobrien    call_site_len = sjlj_size_of_call_site_table ();
392290075Sobrien  else
392390075Sobrien    call_site_len = dw2_size_of_call_site_table ();
392490075Sobrien#endif
392590075Sobrien
392690075Sobrien  /* A pc-relative 4-byte displacement to the @TType data.  */
392790075Sobrien  if (have_tt_data)
392890075Sobrien    {
392990075Sobrien#ifdef HAVE_AS_LEB128
393090075Sobrien      char ttype_after_disp_label[32];
393190075Sobrien      ASM_GENERATE_INTERNAL_LABEL (ttype_after_disp_label, "LLSDATTD",
393290075Sobrien				   funcdef_number);
393390075Sobrien      dw2_asm_output_delta_uleb128 (ttype_label, ttype_after_disp_label,
393490075Sobrien				    "@TType base offset");
393590075Sobrien      ASM_OUTPUT_LABEL (asm_out_file, ttype_after_disp_label);
393690075Sobrien#else
393790075Sobrien      /* Ug.  Alignment queers things.  */
393890075Sobrien      unsigned int before_disp, after_disp, last_disp, disp;
393990075Sobrien
394090075Sobrien      before_disp = 1 + 1;
394190075Sobrien      after_disp = (1 + size_of_uleb128 (call_site_len)
394290075Sobrien		    + call_site_len
394390075Sobrien		    + VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data)
394490075Sobrien		    + (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data)
394590075Sobrien		       * tt_format_size));
394690075Sobrien
394790075Sobrien      disp = after_disp;
394890075Sobrien      do
394990075Sobrien	{
395090075Sobrien	  unsigned int disp_size, pad;
395190075Sobrien
395290075Sobrien	  last_disp = disp;
395390075Sobrien	  disp_size = size_of_uleb128 (disp);
395490075Sobrien	  pad = before_disp + disp_size + after_disp;
395590075Sobrien	  if (pad % tt_format_size)
395690075Sobrien	    pad = tt_format_size - (pad % tt_format_size);
395790075Sobrien	  else
395890075Sobrien	    pad = 0;
395990075Sobrien	  disp = after_disp + pad;
396090075Sobrien	}
396190075Sobrien      while (disp != last_disp);
396290075Sobrien
396390075Sobrien      dw2_asm_output_data_uleb128 (disp, "@TType base offset");
396490075Sobrien#endif
396590075Sobrien    }
396690075Sobrien
396790075Sobrien  /* Indicate the format of the call-site offsets.  */
396890075Sobrien#ifdef HAVE_AS_LEB128
396990075Sobrien  cs_format = DW_EH_PE_uleb128;
397090075Sobrien#else
397190075Sobrien  cs_format = DW_EH_PE_udata4;
397290075Sobrien#endif
397390075Sobrien  dw2_asm_output_data (1, cs_format, "call-site format (%s)",
397490075Sobrien		       eh_data_format_name (cs_format));
397590075Sobrien
397690075Sobrien#ifdef HAVE_AS_LEB128
397790075Sobrien  ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label, "LLSDACSB",
397890075Sobrien			       funcdef_number);
397990075Sobrien  ASM_GENERATE_INTERNAL_LABEL (cs_end_label, "LLSDACSE",
398090075Sobrien			       funcdef_number);
398190075Sobrien  dw2_asm_output_delta_uleb128 (cs_end_label, cs_after_size_label,
398290075Sobrien				"Call-site table length");
398390075Sobrien  ASM_OUTPUT_LABEL (asm_out_file, cs_after_size_label);
398490075Sobrien  if (USING_SJLJ_EXCEPTIONS)
398590075Sobrien    sjlj_output_call_site_table ();
398690075Sobrien  else
398790075Sobrien    dw2_output_call_site_table ();
398890075Sobrien  ASM_OUTPUT_LABEL (asm_out_file, cs_end_label);
398990075Sobrien#else
399090075Sobrien  dw2_asm_output_data_uleb128 (call_site_len,"Call-site table length");
399190075Sobrien  if (USING_SJLJ_EXCEPTIONS)
399290075Sobrien    sjlj_output_call_site_table ();
399390075Sobrien  else
399490075Sobrien    dw2_output_call_site_table ();
399590075Sobrien#endif
399690075Sobrien
399790075Sobrien  /* ??? Decode and interpret the data for flag_debug_asm.  */
399890075Sobrien  n = VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data);
399990075Sobrien  for (i = 0; i < n; ++i)
400090075Sobrien    dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->action_record_data, i),
400190075Sobrien			 (i ? NULL : "Action record table"));
400290075Sobrien
400390075Sobrien  if (have_tt_data)
400490075Sobrien    assemble_align (tt_format_size * BITS_PER_UNIT);
400590075Sobrien
400690075Sobrien  i = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data);
400790075Sobrien  while (i-- > 0)
400890075Sobrien    {
400990075Sobrien      tree type = VARRAY_TREE (cfun->eh->ttype_data, i);
401090075Sobrien      rtx value;
401190075Sobrien
401290075Sobrien      if (type == NULL_TREE)
401390075Sobrien	type = integer_zero_node;
401490075Sobrien      else
401590075Sobrien	type = lookup_type_for_runtime (type);
401690075Sobrien
401790075Sobrien      value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
401890075Sobrien      if (tt_format == DW_EH_PE_absptr || tt_format == DW_EH_PE_aligned)
401990075Sobrien	assemble_integer (value, tt_format_size,
402090075Sobrien			  tt_format_size * BITS_PER_UNIT, 1);
402190075Sobrien      else
402290075Sobrien        dw2_asm_output_encoded_addr_rtx (tt_format, value, NULL);
402390075Sobrien    }
402490075Sobrien
402590075Sobrien#ifdef HAVE_AS_LEB128
402690075Sobrien  if (have_tt_data)
402790075Sobrien      ASM_OUTPUT_LABEL (asm_out_file, ttype_label);
402890075Sobrien#endif
402990075Sobrien
403090075Sobrien  /* ??? Decode and interpret the data for flag_debug_asm.  */
403190075Sobrien  n = VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data);
403290075Sobrien  for (i = 0; i < n; ++i)
403390075Sobrien    dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->ehspec_data, i),
403490075Sobrien			 (i ? NULL : "Exception specification table"));
403590075Sobrien
403690075Sobrien  function_section (current_function_decl);
403790075Sobrien
403890075Sobrien  if (USING_SJLJ_EXCEPTIONS)
403990075Sobrien    sjlj_funcdef_number += 1;
404050397Sobrien}
4041