except.c revision 90075
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
10090075Sobrien/* A list of labels used for exception handlers.  */
10190075Sobrienrtx exception_handler_labels;
10250397Sobrien
10390075Sobrienstatic int call_site_base;
10490075Sobrienstatic unsigned int sjlj_funcdef_number;
10590075Sobrienstatic htab_t type_to_runtime_map;
10650397Sobrien
10790075Sobrien/* Describe the SjLj_Function_Context structure.  */
10890075Sobrienstatic tree sjlj_fc_type_node;
10990075Sobrienstatic int sjlj_fc_call_site_ofs;
11090075Sobrienstatic int sjlj_fc_data_ofs;
11190075Sobrienstatic int sjlj_fc_personality_ofs;
11290075Sobrienstatic int sjlj_fc_lsda_ofs;
11390075Sobrienstatic int sjlj_fc_jbuf_ofs;
11490075Sobrien
11590075Sobrien/* Describes one exception region.  */
11690075Sobrienstruct eh_region
11790075Sobrien{
11890075Sobrien  /* The immediately surrounding region.  */
11990075Sobrien  struct eh_region *outer;
12050397Sobrien
12190075Sobrien  /* The list of immediately contained regions.  */
12290075Sobrien  struct eh_region *inner;
12390075Sobrien  struct eh_region *next_peer;
12450397Sobrien
12590075Sobrien  /* An identifier for this region.  */
12690075Sobrien  int region_number;
12750397Sobrien
12890075Sobrien  /* Each region does exactly one thing.  */
12990075Sobrien  enum eh_region_type
13090075Sobrien  {
13190075Sobrien    ERT_UNKNOWN = 0,
13290075Sobrien    ERT_CLEANUP,
13390075Sobrien    ERT_TRY,
13490075Sobrien    ERT_CATCH,
13590075Sobrien    ERT_ALLOWED_EXCEPTIONS,
13690075Sobrien    ERT_MUST_NOT_THROW,
13790075Sobrien    ERT_THROW,
13890075Sobrien    ERT_FIXUP
13990075Sobrien  } type;
14050397Sobrien
14190075Sobrien  /* Holds the action to perform based on the preceding type.  */
14290075Sobrien  union {
14390075Sobrien    /* A list of catch blocks, a surrounding try block,
14490075Sobrien       and the label for continuing after a catch.  */
14590075Sobrien    struct {
14690075Sobrien      struct eh_region *catch;
14790075Sobrien      struct eh_region *last_catch;
14890075Sobrien      struct eh_region *prev_try;
14990075Sobrien      rtx continue_label;
15090075Sobrien    } try;
15150397Sobrien
15290075Sobrien    /* The list through the catch handlers, the list of type objects
15390075Sobrien       matched, and the list of associated filters.  */
15490075Sobrien    struct {
15590075Sobrien      struct eh_region *next_catch;
15690075Sobrien      struct eh_region *prev_catch;
15790075Sobrien      tree type_list;
15890075Sobrien      tree filter_list;
15990075Sobrien    } catch;
16050397Sobrien
16190075Sobrien    /* A tree_list of allowed types.  */
16290075Sobrien    struct {
16390075Sobrien      tree type_list;
16490075Sobrien      int filter;
16590075Sobrien    } allowed;
16650397Sobrien
16790075Sobrien    /* The type given by a call to "throw foo();", or discovered
16890075Sobrien       for a throw.  */
16990075Sobrien    struct {
17090075Sobrien      tree type;
17190075Sobrien    } throw;
17250397Sobrien
17390075Sobrien    /* Retain the cleanup expression even after expansion so that
17490075Sobrien       we can match up fixup regions.  */
17590075Sobrien    struct {
17690075Sobrien      tree exp;
17790075Sobrien    } cleanup;
17850397Sobrien
17990075Sobrien    /* The real region (by expression and by pointer) that fixup code
18090075Sobrien       should live in.  */
18190075Sobrien    struct {
18290075Sobrien      tree cleanup_exp;
18390075Sobrien      struct eh_region *real_region;
18490075Sobrien    } fixup;
18590075Sobrien  } u;
18650397Sobrien
18790075Sobrien  /* Entry point for this region's handler before landing pads are built.  */
18890075Sobrien  rtx label;
18950397Sobrien
19090075Sobrien  /* Entry point for this region's handler from the runtime eh library.  */
19190075Sobrien  rtx landing_pad;
19250397Sobrien
19390075Sobrien  /* Entry point for this region's handler from an inner region.  */
19490075Sobrien  rtx post_landing_pad;
19550397Sobrien
19690075Sobrien  /* The RESX insn for handing off control to the next outermost handler,
19790075Sobrien     if appropriate.  */
19890075Sobrien  rtx resume;
19990075Sobrien};
20050397Sobrien
20190075Sobrien/* Used to save exception status for each function.  */
20290075Sobrienstruct eh_status
20390075Sobrien{
20490075Sobrien  /* The tree of all regions for this function.  */
20590075Sobrien  struct eh_region *region_tree;
20650397Sobrien
20790075Sobrien  /* The same information as an indexable array.  */
20890075Sobrien  struct eh_region **region_array;
20950397Sobrien
21090075Sobrien  /* The most recently open region.  */
21190075Sobrien  struct eh_region *cur_region;
21250397Sobrien
21390075Sobrien  /* This is the region for which we are processing catch blocks.  */
21490075Sobrien  struct eh_region *try_region;
21550397Sobrien
21690075Sobrien  /* A stack (TREE_LIST) of lists of handlers.  The TREE_VALUE of each
21790075Sobrien     node is itself a TREE_CHAINed list of handlers for regions that
21890075Sobrien     are not yet closed. The TREE_VALUE of each entry contains the
21990075Sobrien     handler for the corresponding entry on the ehstack.  */
22090075Sobrien  tree protect_list;
22150397Sobrien
22290075Sobrien  rtx filter;
22390075Sobrien  rtx exc_ptr;
22450397Sobrien
22590075Sobrien  int built_landing_pads;
22690075Sobrien  int last_region_number;
22750397Sobrien
22890075Sobrien  varray_type ttype_data;
22990075Sobrien  varray_type ehspec_data;
23090075Sobrien  varray_type action_record_data;
23150397Sobrien
23290075Sobrien  struct call_site_record
23390075Sobrien  {
23490075Sobrien    rtx landing_pad;
23590075Sobrien    int action;
23690075Sobrien  } *call_site_data;
23790075Sobrien  int call_site_data_used;
23890075Sobrien  int call_site_data_size;
23950397Sobrien
24090075Sobrien  rtx ehr_stackadj;
24190075Sobrien  rtx ehr_handler;
24290075Sobrien  rtx ehr_label;
24350397Sobrien
24490075Sobrien  rtx sjlj_fc;
24590075Sobrien  rtx sjlj_exit_after;
24690075Sobrien};
24750397Sobrien
24890075Sobrien
24990075Sobrienstatic void mark_eh_region			PARAMS ((struct eh_region *));
25050397Sobrien
25190075Sobrienstatic int t2r_eq				PARAMS ((const PTR,
25290075Sobrien							 const PTR));
25390075Sobrienstatic hashval_t t2r_hash			PARAMS ((const PTR));
25490075Sobrienstatic int t2r_mark_1				PARAMS ((PTR *, PTR));
25590075Sobrienstatic void t2r_mark				PARAMS ((PTR));
25690075Sobrienstatic void add_type_for_runtime		PARAMS ((tree));
25790075Sobrienstatic tree lookup_type_for_runtime		PARAMS ((tree));
25850397Sobrien
25990075Sobrienstatic struct eh_region *expand_eh_region_end	PARAMS ((void));
26050397Sobrien
26190075Sobrienstatic rtx get_exception_filter			PARAMS ((struct function *));
26250397Sobrien
26390075Sobrienstatic void collect_eh_region_array		PARAMS ((void));
26490075Sobrienstatic void resolve_fixup_regions		PARAMS ((void));
26590075Sobrienstatic void remove_fixup_regions		PARAMS ((void));
26690075Sobrienstatic void remove_unreachable_regions		PARAMS ((rtx));
26790075Sobrienstatic void convert_from_eh_region_ranges_1	PARAMS ((rtx *, int *, int));
26850397Sobrien
26990075Sobrienstatic struct eh_region *duplicate_eh_region_1	PARAMS ((struct eh_region *,
27090075Sobrien						     struct inline_remap *));
27190075Sobrienstatic void duplicate_eh_region_2		PARAMS ((struct eh_region *,
27290075Sobrien							 struct eh_region **));
27390075Sobrienstatic int ttypes_filter_eq			PARAMS ((const PTR,
27490075Sobrien							 const PTR));
27590075Sobrienstatic hashval_t ttypes_filter_hash		PARAMS ((const PTR));
27690075Sobrienstatic int ehspec_filter_eq			PARAMS ((const PTR,
27790075Sobrien							 const PTR));
27890075Sobrienstatic hashval_t ehspec_filter_hash		PARAMS ((const PTR));
27990075Sobrienstatic int add_ttypes_entry			PARAMS ((htab_t, tree));
28090075Sobrienstatic int add_ehspec_entry			PARAMS ((htab_t, htab_t,
28190075Sobrien							 tree));
28290075Sobrienstatic void assign_filter_values		PARAMS ((void));
28390075Sobrienstatic void build_post_landing_pads		PARAMS ((void));
28490075Sobrienstatic void connect_post_landing_pads		PARAMS ((void));
28590075Sobrienstatic void dw2_build_landing_pads		PARAMS ((void));
28650397Sobrien
28790075Sobrienstruct sjlj_lp_info;
28890075Sobrienstatic bool sjlj_find_directly_reachable_regions
28990075Sobrien     PARAMS ((struct sjlj_lp_info *));
29090075Sobrienstatic void sjlj_assign_call_site_values
29190075Sobrien     PARAMS ((rtx, struct sjlj_lp_info *));
29290075Sobrienstatic void sjlj_mark_call_sites
29390075Sobrien     PARAMS ((struct sjlj_lp_info *));
29490075Sobrienstatic void sjlj_emit_function_enter		PARAMS ((rtx));
29590075Sobrienstatic void sjlj_emit_function_exit		PARAMS ((void));
29690075Sobrienstatic void sjlj_emit_dispatch_table
29790075Sobrien     PARAMS ((rtx, struct sjlj_lp_info *));
29890075Sobrienstatic void sjlj_build_landing_pads		PARAMS ((void));
29950397Sobrien
30090075Sobrienstatic void remove_exception_handler_label	PARAMS ((rtx));
30190075Sobrienstatic void remove_eh_handler			PARAMS ((struct eh_region *));
30250397Sobrien
30390075Sobrienstruct reachable_info;
30450397Sobrien
30590075Sobrien/* The return value of reachable_next_level.  */
30690075Sobrienenum reachable_code
30790075Sobrien{
30890075Sobrien  /* The given exception is not processed by the given region.  */
30990075Sobrien  RNL_NOT_CAUGHT,
31090075Sobrien  /* The given exception may need processing by the given region.  */
31190075Sobrien  RNL_MAYBE_CAUGHT,
31290075Sobrien  /* The given exception is completely processed by the given region.  */
31390075Sobrien  RNL_CAUGHT,
31490075Sobrien  /* The given exception is completely processed by the runtime.  */
31590075Sobrien  RNL_BLOCKED
31690075Sobrien};
31750397Sobrien
31890075Sobrienstatic int check_handled			PARAMS ((tree, tree));
31990075Sobrienstatic void add_reachable_handler
32090075Sobrien     PARAMS ((struct reachable_info *, struct eh_region *,
32190075Sobrien	      struct eh_region *));
32290075Sobrienstatic enum reachable_code reachable_next_level
32390075Sobrien     PARAMS ((struct eh_region *, tree, struct reachable_info *));
32450397Sobrien
32590075Sobrienstatic int action_record_eq			PARAMS ((const PTR,
32690075Sobrien							 const PTR));
32790075Sobrienstatic hashval_t action_record_hash		PARAMS ((const PTR));
32890075Sobrienstatic int add_action_record			PARAMS ((htab_t, int, int));
32990075Sobrienstatic int collect_one_action_chain		PARAMS ((htab_t,
33090075Sobrien							 struct eh_region *));
33190075Sobrienstatic int add_call_site			PARAMS ((rtx, int));
33250397Sobrien
33390075Sobrienstatic void push_uleb128			PARAMS ((varray_type *,
33490075Sobrien							 unsigned int));
33590075Sobrienstatic void push_sleb128			PARAMS ((varray_type *, int));
33690075Sobrien#ifndef HAVE_AS_LEB128
33790075Sobrienstatic int dw2_size_of_call_site_table		PARAMS ((void));
33890075Sobrienstatic int sjlj_size_of_call_site_table		PARAMS ((void));
33990075Sobrien#endif
34090075Sobrienstatic void dw2_output_call_site_table		PARAMS ((void));
34190075Sobrienstatic void sjlj_output_call_site_table		PARAMS ((void));
34250397Sobrien
34390075Sobrien
34490075Sobrien/* Routine to see if exception handling is turned on.
34590075Sobrien   DO_WARN is non-zero if we want to inform the user that exception
34690075Sobrien   handling is turned off.
34750397Sobrien
34890075Sobrien   This is used to ensure that -fexceptions has been specified if the
34990075Sobrien   compiler tries to use any exception-specific functions.  */
35050397Sobrien
35190075Sobrienint
35290075Sobriendoing_eh (do_warn)
35390075Sobrien     int do_warn;
35490075Sobrien{
35590075Sobrien  if (! flag_exceptions)
35690075Sobrien    {
35790075Sobrien      static int warned = 0;
35890075Sobrien      if (! warned && do_warn)
35990075Sobrien	{
36090075Sobrien	  error ("exception handling disabled, use -fexceptions to enable");
36190075Sobrien	  warned = 1;
36290075Sobrien	}
36390075Sobrien      return 0;
36490075Sobrien    }
36590075Sobrien  return 1;
36690075Sobrien}
36750397Sobrien
36890075Sobrien
36990075Sobrienvoid
37090075Sobrieninit_eh ()
37190075Sobrien{
37290075Sobrien  ggc_add_rtx_root (&exception_handler_labels, 1);
37350397Sobrien
37490075Sobrien  if (! flag_exceptions)
37590075Sobrien    return;
37650397Sobrien
37790075Sobrien  type_to_runtime_map = htab_create (31, t2r_hash, t2r_eq, NULL);
37890075Sobrien  ggc_add_root (&type_to_runtime_map, 1, sizeof (htab_t), t2r_mark);
37950397Sobrien
38090075Sobrien  /* Create the SjLj_Function_Context structure.  This should match
38190075Sobrien     the definition in unwind-sjlj.c.  */
38290075Sobrien  if (USING_SJLJ_EXCEPTIONS)
38390075Sobrien    {
38490075Sobrien      tree f_jbuf, f_per, f_lsda, f_prev, f_cs, f_data, tmp;
38550397Sobrien
38690075Sobrien      sjlj_fc_type_node = make_lang_type (RECORD_TYPE);
38790075Sobrien      ggc_add_tree_root (&sjlj_fc_type_node, 1);
38850397Sobrien
38990075Sobrien      f_prev = build_decl (FIELD_DECL, get_identifier ("__prev"),
39090075Sobrien			   build_pointer_type (sjlj_fc_type_node));
39190075Sobrien      DECL_FIELD_CONTEXT (f_prev) = sjlj_fc_type_node;
39250397Sobrien
39390075Sobrien      f_cs = build_decl (FIELD_DECL, get_identifier ("__call_site"),
39490075Sobrien			 integer_type_node);
39590075Sobrien      DECL_FIELD_CONTEXT (f_cs) = sjlj_fc_type_node;
39650397Sobrien
39790075Sobrien      tmp = build_index_type (build_int_2 (4 - 1, 0));
39890075Sobrien      tmp = build_array_type (type_for_mode (word_mode, 1), tmp);
39990075Sobrien      f_data = build_decl (FIELD_DECL, get_identifier ("__data"), tmp);
40090075Sobrien      DECL_FIELD_CONTEXT (f_data) = sjlj_fc_type_node;
40150397Sobrien
40290075Sobrien      f_per = build_decl (FIELD_DECL, get_identifier ("__personality"),
40390075Sobrien			  ptr_type_node);
40490075Sobrien      DECL_FIELD_CONTEXT (f_per) = sjlj_fc_type_node;
40550397Sobrien
40690075Sobrien      f_lsda = build_decl (FIELD_DECL, get_identifier ("__lsda"),
40790075Sobrien			   ptr_type_node);
40890075Sobrien      DECL_FIELD_CONTEXT (f_lsda) = sjlj_fc_type_node;
40950397Sobrien
41090075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP
41190075Sobrien#ifdef JMP_BUF_SIZE
41290075Sobrien      tmp = build_int_2 (JMP_BUF_SIZE - 1, 0);
41390075Sobrien#else
41490075Sobrien      /* Should be large enough for most systems, if it is not,
41590075Sobrien	 JMP_BUF_SIZE should be defined with the proper value.  It will
41690075Sobrien	 also tend to be larger than necessary for most systems, a more
41790075Sobrien	 optimal port will define JMP_BUF_SIZE.  */
41890075Sobrien      tmp = build_int_2 (FIRST_PSEUDO_REGISTER + 2 - 1, 0);
41990075Sobrien#endif
42090075Sobrien#else
42190075Sobrien      /* This is 2 for builtin_setjmp, plus whatever the target requires
42290075Sobrien	 via STACK_SAVEAREA_MODE (SAVE_NONLOCAL).  */
42390075Sobrien      tmp = build_int_2 ((GET_MODE_SIZE (STACK_SAVEAREA_MODE (SAVE_NONLOCAL))
42490075Sobrien			  / GET_MODE_SIZE (Pmode)) + 2 - 1, 0);
42590075Sobrien#endif
42690075Sobrien      tmp = build_index_type (tmp);
42790075Sobrien      tmp = build_array_type (ptr_type_node, tmp);
42890075Sobrien      f_jbuf = build_decl (FIELD_DECL, get_identifier ("__jbuf"), tmp);
42990075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP
43090075Sobrien      /* We don't know what the alignment requirements of the
43190075Sobrien	 runtime's jmp_buf has.  Overestimate.  */
43290075Sobrien      DECL_ALIGN (f_jbuf) = BIGGEST_ALIGNMENT;
43390075Sobrien      DECL_USER_ALIGN (f_jbuf) = 1;
43490075Sobrien#endif
43590075Sobrien      DECL_FIELD_CONTEXT (f_jbuf) = sjlj_fc_type_node;
43650397Sobrien
43790075Sobrien      TYPE_FIELDS (sjlj_fc_type_node) = f_prev;
43890075Sobrien      TREE_CHAIN (f_prev) = f_cs;
43990075Sobrien      TREE_CHAIN (f_cs) = f_data;
44090075Sobrien      TREE_CHAIN (f_data) = f_per;
44190075Sobrien      TREE_CHAIN (f_per) = f_lsda;
44290075Sobrien      TREE_CHAIN (f_lsda) = f_jbuf;
44350397Sobrien
44490075Sobrien      layout_type (sjlj_fc_type_node);
44550397Sobrien
44690075Sobrien      /* Cache the interesting field offsets so that we have
44790075Sobrien	 easy access from rtl.  */
44890075Sobrien      sjlj_fc_call_site_ofs
44990075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_cs), 1)
45090075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_cs), 1) / BITS_PER_UNIT);
45190075Sobrien      sjlj_fc_data_ofs
45290075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_data), 1)
45390075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_data), 1) / BITS_PER_UNIT);
45490075Sobrien      sjlj_fc_personality_ofs
45590075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_per), 1)
45690075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_per), 1) / BITS_PER_UNIT);
45790075Sobrien      sjlj_fc_lsda_ofs
45890075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_lsda), 1)
45990075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_lsda), 1) / BITS_PER_UNIT);
46090075Sobrien      sjlj_fc_jbuf_ofs
46190075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_jbuf), 1)
46290075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_jbuf), 1) / BITS_PER_UNIT);
46390075Sobrien    }
46490075Sobrien}
46550397Sobrien
46690075Sobrienvoid
46790075Sobrieninit_eh_for_function ()
46890075Sobrien{
46990075Sobrien  cfun->eh = (struct eh_status *) xcalloc (1, sizeof (struct eh_status));
47090075Sobrien}
47150397Sobrien
47290075Sobrien/* Mark EH for GC.  */
47350397Sobrien
47490075Sobrienstatic void
47590075Sobrienmark_eh_region (region)
47690075Sobrien     struct eh_region *region;
47790075Sobrien{
47890075Sobrien  if (! region)
47990075Sobrien    return;
48050397Sobrien
48190075Sobrien  switch (region->type)
48290075Sobrien    {
48390075Sobrien    case ERT_UNKNOWN:
48490075Sobrien      /* This can happen if a nested function is inside the body of a region
48590075Sobrien	 and we do a GC as part of processing it.  */
48690075Sobrien      break;
48790075Sobrien    case ERT_CLEANUP:
48890075Sobrien      ggc_mark_tree (region->u.cleanup.exp);
48990075Sobrien      break;
49090075Sobrien    case ERT_TRY:
49190075Sobrien      ggc_mark_rtx (region->u.try.continue_label);
49290075Sobrien      break;
49390075Sobrien    case ERT_CATCH:
49490075Sobrien      ggc_mark_tree (region->u.catch.type_list);
49590075Sobrien      ggc_mark_tree (region->u.catch.filter_list);
49690075Sobrien      break;
49790075Sobrien    case ERT_ALLOWED_EXCEPTIONS:
49890075Sobrien      ggc_mark_tree (region->u.allowed.type_list);
49990075Sobrien      break;
50090075Sobrien    case ERT_MUST_NOT_THROW:
50190075Sobrien      break;
50290075Sobrien    case ERT_THROW:
50390075Sobrien      ggc_mark_tree (region->u.throw.type);
50490075Sobrien      break;
50590075Sobrien    case ERT_FIXUP:
50690075Sobrien      ggc_mark_tree (region->u.fixup.cleanup_exp);
50790075Sobrien      break;
50890075Sobrien    default:
50990075Sobrien      abort ();
51090075Sobrien    }
51150397Sobrien
51290075Sobrien  ggc_mark_rtx (region->label);
51390075Sobrien  ggc_mark_rtx (region->resume);
51490075Sobrien  ggc_mark_rtx (region->landing_pad);
51590075Sobrien  ggc_mark_rtx (region->post_landing_pad);
51690075Sobrien}
51750397Sobrien
51890075Sobrienvoid
51990075Sobrienmark_eh_status (eh)
52090075Sobrien     struct eh_status *eh;
52190075Sobrien{
52290075Sobrien  int i;
52350397Sobrien
52490075Sobrien  if (eh == 0)
52590075Sobrien    return;
52650397Sobrien
52790075Sobrien  /* If we've called collect_eh_region_array, use it.  Otherwise walk
52890075Sobrien     the tree non-recursively.  */
52990075Sobrien  if (eh->region_array)
53090075Sobrien    {
53190075Sobrien      for (i = eh->last_region_number; i > 0; --i)
53290075Sobrien	{
53390075Sobrien	  struct eh_region *r = eh->region_array[i];
53490075Sobrien	  if (r && r->region_number == i)
53590075Sobrien	    mark_eh_region (r);
53690075Sobrien	}
53790075Sobrien    }
53890075Sobrien  else if (eh->region_tree)
53990075Sobrien    {
54090075Sobrien      struct eh_region *r = eh->region_tree;
54190075Sobrien      while (1)
54290075Sobrien	{
54390075Sobrien	  mark_eh_region (r);
54490075Sobrien	  if (r->inner)
54590075Sobrien	    r = r->inner;
54690075Sobrien	  else if (r->next_peer)
54790075Sobrien	    r = r->next_peer;
54890075Sobrien	  else
54990075Sobrien	    {
55090075Sobrien	      do {
55190075Sobrien		r = r->outer;
55290075Sobrien		if (r == NULL)
55390075Sobrien		  goto tree_done;
55490075Sobrien	      } while (r->next_peer == NULL);
55590075Sobrien	      r = r->next_peer;
55690075Sobrien	    }
55790075Sobrien	}
55890075Sobrien    tree_done:;
55990075Sobrien    }
56050397Sobrien
56190075Sobrien  ggc_mark_tree (eh->protect_list);
56290075Sobrien  ggc_mark_rtx (eh->filter);
56390075Sobrien  ggc_mark_rtx (eh->exc_ptr);
56490075Sobrien  ggc_mark_tree_varray (eh->ttype_data);
56550397Sobrien
56690075Sobrien  if (eh->call_site_data)
56790075Sobrien    {
56890075Sobrien      for (i = eh->call_site_data_used - 1; i >= 0; --i)
56990075Sobrien	ggc_mark_rtx (eh->call_site_data[i].landing_pad);
57090075Sobrien    }
57150397Sobrien
57290075Sobrien  ggc_mark_rtx (eh->ehr_stackadj);
57390075Sobrien  ggc_mark_rtx (eh->ehr_handler);
57490075Sobrien  ggc_mark_rtx (eh->ehr_label);
57550397Sobrien
57690075Sobrien  ggc_mark_rtx (eh->sjlj_fc);
57790075Sobrien  ggc_mark_rtx (eh->sjlj_exit_after);
57890075Sobrien}
57950397Sobrien
58090075Sobrienvoid
58190075Sobrienfree_eh_status (f)
58290075Sobrien     struct function *f;
58390075Sobrien{
58490075Sobrien  struct eh_status *eh = f->eh;
58550397Sobrien
58690075Sobrien  if (eh->region_array)
58790075Sobrien    {
58890075Sobrien      int i;
58990075Sobrien      for (i = eh->last_region_number; i > 0; --i)
59090075Sobrien	{
59190075Sobrien	  struct eh_region *r = eh->region_array[i];
59290075Sobrien	  /* Mind we don't free a region struct more than once.  */
59390075Sobrien	  if (r && r->region_number == i)
59490075Sobrien	    free (r);
59590075Sobrien	}
59690075Sobrien      free (eh->region_array);
59790075Sobrien    }
59890075Sobrien  else if (eh->region_tree)
59990075Sobrien    {
60090075Sobrien      struct eh_region *next, *r = eh->region_tree;
60190075Sobrien      while (1)
60290075Sobrien	{
60390075Sobrien	  if (r->inner)
60490075Sobrien	    r = r->inner;
60590075Sobrien	  else if (r->next_peer)
60690075Sobrien	    {
60790075Sobrien	      next = r->next_peer;
60890075Sobrien	      free (r);
60990075Sobrien	      r = next;
61090075Sobrien	    }
61190075Sobrien	  else
61290075Sobrien	    {
61390075Sobrien	      do {
61490075Sobrien	        next = r->outer;
61590075Sobrien	        free (r);
61690075Sobrien	        r = next;
61790075Sobrien		if (r == NULL)
61890075Sobrien		  goto tree_done;
61990075Sobrien	      } while (r->next_peer == NULL);
62090075Sobrien	      next = r->next_peer;
62190075Sobrien	      free (r);
62290075Sobrien	      r = next;
62390075Sobrien	    }
62490075Sobrien	}
62590075Sobrien    tree_done:;
62690075Sobrien    }
62750397Sobrien
62890075Sobrien  VARRAY_FREE (eh->ttype_data);
62990075Sobrien  VARRAY_FREE (eh->ehspec_data);
63090075Sobrien  VARRAY_FREE (eh->action_record_data);
63190075Sobrien  if (eh->call_site_data)
63290075Sobrien    free (eh->call_site_data);
63350397Sobrien
63490075Sobrien  free (eh);
63590075Sobrien  f->eh = NULL;
63690075Sobrien  exception_handler_labels = NULL;
63790075Sobrien}
63850397Sobrien
63990075Sobrien
64090075Sobrien/* Start an exception handling region.  All instructions emitted
64190075Sobrien   after this point are considered to be part of the region until
64290075Sobrien   expand_eh_region_end is invoked.  */
64350397Sobrien
64490075Sobrienvoid
64590075Sobrienexpand_eh_region_start ()
64690075Sobrien{
64790075Sobrien  struct eh_region *new_region;
64890075Sobrien  struct eh_region *cur_region;
64990075Sobrien  rtx note;
65052284Sobrien
65190075Sobrien  if (! doing_eh (0))
65290075Sobrien    return;
65352284Sobrien
65490075Sobrien  /* Insert a new blank region as a leaf in the tree.  */
65590075Sobrien  new_region = (struct eh_region *) xcalloc (1, sizeof (*new_region));
65690075Sobrien  cur_region = cfun->eh->cur_region;
65790075Sobrien  new_region->outer = cur_region;
65890075Sobrien  if (cur_region)
65990075Sobrien    {
66090075Sobrien      new_region->next_peer = cur_region->inner;
66190075Sobrien      cur_region->inner = new_region;
66290075Sobrien    }
66390075Sobrien  else
66490075Sobrien    {
66590075Sobrien      new_region->next_peer = cfun->eh->region_tree;
66690075Sobrien      cfun->eh->region_tree = new_region;
66790075Sobrien    }
66890075Sobrien  cfun->eh->cur_region = new_region;
66952284Sobrien
67090075Sobrien  /* Create a note marking the start of this region.  */
67190075Sobrien  new_region->region_number = ++cfun->eh->last_region_number;
67290075Sobrien  note = emit_note (NULL, NOTE_INSN_EH_REGION_BEG);
67390075Sobrien  NOTE_EH_HANDLER (note) = new_region->region_number;
67490075Sobrien}
67552284Sobrien
67690075Sobrien/* Common code to end a region.  Returns the region just ended.  */
67752284Sobrien
67890075Sobrienstatic struct eh_region *
67990075Sobrienexpand_eh_region_end ()
68090075Sobrien{
68190075Sobrien  struct eh_region *cur_region = cfun->eh->cur_region;
68290075Sobrien  rtx note;
68352284Sobrien
68490075Sobrien  /* Create a note marking the end of this region.  */
68590075Sobrien  note = emit_note (NULL, NOTE_INSN_EH_REGION_END);
68690075Sobrien  NOTE_EH_HANDLER (note) = cur_region->region_number;
68752284Sobrien
68890075Sobrien  /* Pop.  */
68990075Sobrien  cfun->eh->cur_region = cur_region->outer;
69052284Sobrien
69190075Sobrien  return cur_region;
69290075Sobrien}
69350397Sobrien
69490075Sobrien/* End an exception handling region for a cleanup.  HANDLER is an
69590075Sobrien   expression to expand for the cleanup.  */
69650397Sobrien
69790075Sobrienvoid
69890075Sobrienexpand_eh_region_end_cleanup (handler)
69990075Sobrien     tree handler;
70052284Sobrien{
70190075Sobrien  struct eh_region *region;
70290075Sobrien  tree protect_cleanup_actions;
70390075Sobrien  rtx around_label;
70490075Sobrien  rtx data_save[2];
70552284Sobrien
70690075Sobrien  if (! doing_eh (0))
70790075Sobrien    return;
70852284Sobrien
70990075Sobrien  region = expand_eh_region_end ();
71090075Sobrien  region->type = ERT_CLEANUP;
71190075Sobrien  region->label = gen_label_rtx ();
71290075Sobrien  region->u.cleanup.exp = handler;
71352284Sobrien
71490075Sobrien  around_label = gen_label_rtx ();
71590075Sobrien  emit_jump (around_label);
71652284Sobrien
71790075Sobrien  emit_label (region->label);
71850397Sobrien
71990075Sobrien  /* Give the language a chance to specify an action to be taken if an
72090075Sobrien     exception is thrown that would propagate out of the HANDLER.  */
72190075Sobrien  protect_cleanup_actions
72290075Sobrien    = (lang_protect_cleanup_actions
72390075Sobrien       ? (*lang_protect_cleanup_actions) ()
72490075Sobrien       : NULL_TREE);
72550397Sobrien
72690075Sobrien  if (protect_cleanup_actions)
72790075Sobrien    expand_eh_region_start ();
72850397Sobrien
72990075Sobrien  /* In case this cleanup involves an inline destructor with a try block in
73090075Sobrien     it, we need to save the EH return data registers around it.  */
73190075Sobrien  data_save[0] = gen_reg_rtx (Pmode);
73290075Sobrien  emit_move_insn (data_save[0], get_exception_pointer (cfun));
73390075Sobrien  data_save[1] = gen_reg_rtx (word_mode);
73490075Sobrien  emit_move_insn (data_save[1], get_exception_filter (cfun));
73550397Sobrien
73690075Sobrien  expand_expr (handler, const0_rtx, VOIDmode, 0);
73750397Sobrien
73890075Sobrien  emit_move_insn (cfun->eh->exc_ptr, data_save[0]);
73990075Sobrien  emit_move_insn (cfun->eh->filter, data_save[1]);
74050397Sobrien
74190075Sobrien  if (protect_cleanup_actions)
74290075Sobrien    expand_eh_region_end_must_not_throw (protect_cleanup_actions);
74350397Sobrien
74490075Sobrien  /* We need any stack adjustment complete before the around_label.  */
74590075Sobrien  do_pending_stack_adjust ();
74690075Sobrien
74790075Sobrien  /* We delay the generation of the _Unwind_Resume until we generate
74890075Sobrien     landing pads.  We emit a marker here so as to get good control
74990075Sobrien     flow data in the meantime.  */
75090075Sobrien  region->resume
75190075Sobrien    = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
75290075Sobrien  emit_barrier ();
75390075Sobrien
75490075Sobrien  emit_label (around_label);
75550397Sobrien}
75650397Sobrien
75790075Sobrien/* End an exception handling region for a try block, and prepares
75890075Sobrien   for subsequent calls to expand_start_catch.  */
75950397Sobrien
76090075Sobrienvoid
76190075Sobrienexpand_start_all_catch ()
76250397Sobrien{
76390075Sobrien  struct eh_region *region;
76450397Sobrien
76590075Sobrien  if (! doing_eh (1))
76690075Sobrien    return;
76750397Sobrien
76890075Sobrien  region = expand_eh_region_end ();
76990075Sobrien  region->type = ERT_TRY;
77090075Sobrien  region->u.try.prev_try = cfun->eh->try_region;
77190075Sobrien  region->u.try.continue_label = gen_label_rtx ();
77250397Sobrien
77390075Sobrien  cfun->eh->try_region = region;
77490075Sobrien
77590075Sobrien  emit_jump (region->u.try.continue_label);
77650397Sobrien}
77750397Sobrien
77890075Sobrien/* Begin a catch clause.  TYPE is the type caught, a list of such types, or
77990075Sobrien   null if this is a catch-all clause. Providing a type list enables to
78090075Sobrien   associate the catch region with potentially several exception types, which
78190075Sobrien   is useful e.g. for Ada.  */
78250397Sobrien
78390075Sobrienvoid
78490075Sobrienexpand_start_catch (type_or_list)
78590075Sobrien     tree type_or_list;
78650397Sobrien{
78790075Sobrien  struct eh_region *t, *c, *l;
78890075Sobrien  tree type_list;
78950397Sobrien
79090075Sobrien  if (! doing_eh (0))
79190075Sobrien    return;
79290075Sobrien
79390075Sobrien  type_list = type_or_list;
79490075Sobrien
79590075Sobrien  if (type_or_list)
79690075Sobrien    {
79790075Sobrien      /* Ensure to always end up with a type list to normalize further
79890075Sobrien         processing, then register each type against the runtime types
79990075Sobrien         map.  */
80090075Sobrien      tree type_node;
80190075Sobrien
80290075Sobrien      if (TREE_CODE (type_or_list) != TREE_LIST)
80390075Sobrien        type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE);
80490075Sobrien
80590075Sobrien      type_node = type_list;
80690075Sobrien      for (; type_node; type_node = TREE_CHAIN (type_node))
80790075Sobrien        add_type_for_runtime (TREE_VALUE (type_node));
80890075Sobrien    }
80990075Sobrien
81090075Sobrien  expand_eh_region_start ();
81190075Sobrien
81290075Sobrien  t = cfun->eh->try_region;
81390075Sobrien  c = cfun->eh->cur_region;
81490075Sobrien  c->type = ERT_CATCH;
81590075Sobrien  c->u.catch.type_list = type_list;
81690075Sobrien  c->label = gen_label_rtx ();
81790075Sobrien
81890075Sobrien  l = t->u.try.last_catch;
81990075Sobrien  c->u.catch.prev_catch = l;
82090075Sobrien  if (l)
82190075Sobrien    l->u.catch.next_catch = c;
82252284Sobrien  else
82390075Sobrien    t->u.try.catch = c;
82490075Sobrien  t->u.try.last_catch = c;
82550397Sobrien
82690075Sobrien  emit_label (c->label);
82750397Sobrien}
82850397Sobrien
82990075Sobrien/* End a catch clause.  Control will resume after the try/catch block.  */
83090075Sobrien
83190075Sobrienvoid
83290075Sobrienexpand_end_catch ()
83350397Sobrien{
83490075Sobrien  struct eh_region *try_region, *catch_region;
83550397Sobrien
83690075Sobrien  if (! doing_eh (0))
83790075Sobrien    return;
83850397Sobrien
83990075Sobrien  catch_region = expand_eh_region_end ();
84090075Sobrien  try_region = cfun->eh->try_region;
84150397Sobrien
84290075Sobrien  emit_jump (try_region->u.try.continue_label);
84350397Sobrien}
84450397Sobrien
84590075Sobrien/* End a sequence of catch handlers for a try block.  */
84650397Sobrien
84790075Sobrienvoid
84890075Sobrienexpand_end_all_catch ()
84950397Sobrien{
85090075Sobrien  struct eh_region *try_region;
85150397Sobrien
85290075Sobrien  if (! doing_eh (0))
85390075Sobrien    return;
85450397Sobrien
85590075Sobrien  try_region = cfun->eh->try_region;
85690075Sobrien  cfun->eh->try_region = try_region->u.try.prev_try;
85790075Sobrien
85890075Sobrien  emit_label (try_region->u.try.continue_label);
85950397Sobrien}
86050397Sobrien
86190075Sobrien/* End an exception region for an exception type filter.  ALLOWED is a
86290075Sobrien   TREE_LIST of types to be matched by the runtime.  FAILURE is an
86390075Sobrien   expression to invoke if a mismatch occurs.
86450397Sobrien
86590075Sobrien   ??? We could use these semantics for calls to rethrow, too; if we can
86690075Sobrien   see the surrounding catch clause, we know that the exception we're
86790075Sobrien   rethrowing satisfies the "filter" of the catch type.  */
86890075Sobrien
86990075Sobrienvoid
87090075Sobrienexpand_eh_region_end_allowed (allowed, failure)
87190075Sobrien     tree allowed, failure;
87250397Sobrien{
87390075Sobrien  struct eh_region *region;
87490075Sobrien  rtx around_label;
87550397Sobrien
87690075Sobrien  if (! doing_eh (0))
87790075Sobrien    return;
87850397Sobrien
87990075Sobrien  region = expand_eh_region_end ();
88090075Sobrien  region->type = ERT_ALLOWED_EXCEPTIONS;
88190075Sobrien  region->u.allowed.type_list = allowed;
88290075Sobrien  region->label = gen_label_rtx ();
88350397Sobrien
88490075Sobrien  for (; allowed ; allowed = TREE_CHAIN (allowed))
88590075Sobrien    add_type_for_runtime (TREE_VALUE (allowed));
88650397Sobrien
88790075Sobrien  /* We must emit the call to FAILURE here, so that if this function
88890075Sobrien     throws a different exception, that it will be processed by the
88990075Sobrien     correct region.  */
89090075Sobrien
89190075Sobrien  around_label = gen_label_rtx ();
89290075Sobrien  emit_jump (around_label);
89390075Sobrien
89490075Sobrien  emit_label (region->label);
89590075Sobrien  expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL);
89690075Sobrien  /* We must adjust the stack before we reach the AROUND_LABEL because
89790075Sobrien     the call to FAILURE does not occur on all paths to the
89890075Sobrien     AROUND_LABEL.  */
89990075Sobrien  do_pending_stack_adjust ();
90090075Sobrien
90190075Sobrien  emit_label (around_label);
90250397Sobrien}
90350397Sobrien
90490075Sobrien/* End an exception region for a must-not-throw filter.  FAILURE is an
90590075Sobrien   expression invoke if an uncaught exception propagates this far.
90690075Sobrien
90790075Sobrien   This is conceptually identical to expand_eh_region_end_allowed with
90890075Sobrien   an empty allowed list (if you passed "std::terminate" instead of
90990075Sobrien   "__cxa_call_unexpected"), but they are represented differently in
91090075Sobrien   the C++ LSDA.  */
91190075Sobrien
91290075Sobrienvoid
91390075Sobrienexpand_eh_region_end_must_not_throw (failure)
91490075Sobrien     tree failure;
91550397Sobrien{
91690075Sobrien  struct eh_region *region;
91790075Sobrien  rtx around_label;
91874722Sobrien
91990075Sobrien  if (! doing_eh (0))
92090075Sobrien    return;
92174722Sobrien
92290075Sobrien  region = expand_eh_region_end ();
92390075Sobrien  region->type = ERT_MUST_NOT_THROW;
92490075Sobrien  region->label = gen_label_rtx ();
92574722Sobrien
92690075Sobrien  /* We must emit the call to FAILURE here, so that if this function
92790075Sobrien     throws a different exception, that it will be processed by the
92890075Sobrien     correct region.  */
92990075Sobrien
93090075Sobrien  around_label = gen_label_rtx ();
93190075Sobrien  emit_jump (around_label);
93290075Sobrien
93390075Sobrien  emit_label (region->label);
93490075Sobrien  expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL);
93590075Sobrien
93690075Sobrien  emit_label (around_label);
93750397Sobrien}
93850397Sobrien
93990075Sobrien/* End an exception region for a throw.  No handling goes on here,
94090075Sobrien   but it's the easiest way for the front-end to indicate what type
94190075Sobrien   is being thrown.  */
94290075Sobrien
94390075Sobrienvoid
94490075Sobrienexpand_eh_region_end_throw (type)
94590075Sobrien     tree type;
94650397Sobrien{
94790075Sobrien  struct eh_region *region;
94850397Sobrien
94990075Sobrien  if (! doing_eh (0))
95090075Sobrien    return;
95150397Sobrien
95290075Sobrien  region = expand_eh_region_end ();
95390075Sobrien  region->type = ERT_THROW;
95490075Sobrien  region->u.throw.type = type;
95590075Sobrien}
95650397Sobrien
95790075Sobrien/* End a fixup region.  Within this region the cleanups for the immediately
95890075Sobrien   enclosing region are _not_ run.  This is used for goto cleanup to avoid
95990075Sobrien   destroying an object twice.
96050397Sobrien
96190075Sobrien   This would be an extraordinarily simple prospect, were it not for the
96290075Sobrien   fact that we don't actually know what the immediately enclosing region
96390075Sobrien   is.  This surprising fact is because expand_cleanups is currently
96490075Sobrien   generating a sequence that it will insert somewhere else.  We collect
96590075Sobrien   the proper notion of "enclosing" in convert_from_eh_region_ranges.  */
96650397Sobrien
96790075Sobrienvoid
96890075Sobrienexpand_eh_region_end_fixup (handler)
96990075Sobrien     tree handler;
97050397Sobrien{
97190075Sobrien  struct eh_region *fixup;
97250397Sobrien
97390075Sobrien  if (! doing_eh (0))
97490075Sobrien    return;
97590075Sobrien
97690075Sobrien  fixup = expand_eh_region_end ();
97790075Sobrien  fixup->type = ERT_FIXUP;
97890075Sobrien  fixup->u.fixup.cleanup_exp = handler;
97950397Sobrien}
98050397Sobrien
98190075Sobrien/* Return an rtl expression for a pointer to the exception object
98290075Sobrien   within a handler.  */
98350397Sobrien
98490075Sobrienrtx
98590075Sobrienget_exception_pointer (fun)
98690075Sobrien     struct function *fun;
98750397Sobrien{
98890075Sobrien  rtx exc_ptr = fun->eh->exc_ptr;
98990075Sobrien  if (fun == cfun && ! exc_ptr)
99050397Sobrien    {
99190075Sobrien      exc_ptr = gen_reg_rtx (Pmode);
99290075Sobrien      fun->eh->exc_ptr = exc_ptr;
99350397Sobrien    }
99490075Sobrien  return exc_ptr;
99550397Sobrien}
99650397Sobrien
99790075Sobrien/* Return an rtl expression for the exception dispatch filter
99890075Sobrien   within a handler.  */
99950397Sobrien
100090075Sobrienstatic rtx
100190075Sobrienget_exception_filter (fun)
100290075Sobrien     struct function *fun;
100350397Sobrien{
100490075Sobrien  rtx filter = fun->eh->filter;
100590075Sobrien  if (fun == cfun && ! filter)
100650397Sobrien    {
100790075Sobrien      filter = gen_reg_rtx (word_mode);
100890075Sobrien      fun->eh->filter = filter;
100950397Sobrien    }
101090075Sobrien  return filter;
101150397Sobrien}
101290075Sobrien
101390075Sobrien/* Begin a region that will contain entries created with
101490075Sobrien   add_partial_entry.  */
101550397Sobrien
101690075Sobrienvoid
101790075Sobrienbegin_protect_partials ()
101850397Sobrien{
101990075Sobrien  /* Push room for a new list.  */
102090075Sobrien  cfun->eh->protect_list
102190075Sobrien    = tree_cons (NULL_TREE, NULL_TREE, cfun->eh->protect_list);
102290075Sobrien}
102350397Sobrien
102490075Sobrien/* Start a new exception region for a region of code that has a
102590075Sobrien   cleanup action and push the HANDLER for the region onto
102690075Sobrien   protect_list. All of the regions created with add_partial_entry
102790075Sobrien   will be ended when end_protect_partials is invoked.
102850397Sobrien
102990075Sobrien   ??? The only difference between this purpose and that of
103090075Sobrien   expand_decl_cleanup is that in this case, we only want the cleanup to
103190075Sobrien   run if an exception is thrown.  This should also be handled using
103290075Sobrien   binding levels.  */
103350397Sobrien
103490075Sobrienvoid
103590075Sobrienadd_partial_entry (handler)
103690075Sobrien     tree handler;
103790075Sobrien{
103890075Sobrien  expand_eh_region_start ();
103950397Sobrien
104090075Sobrien  /* Add this entry to the front of the list.  */
104190075Sobrien  TREE_VALUE (cfun->eh->protect_list)
104290075Sobrien    = tree_cons (NULL_TREE, handler, TREE_VALUE (cfun->eh->protect_list));
104390075Sobrien}
104450397Sobrien
104590075Sobrien/* End all the pending exception regions on protect_list.  */
104650397Sobrien
104790075Sobrienvoid
104890075Sobrienend_protect_partials ()
104990075Sobrien{
105090075Sobrien  tree t;
105150397Sobrien
105290075Sobrien  /* Pop the topmost entry.  */
105390075Sobrien  t = TREE_VALUE (cfun->eh->protect_list);
105490075Sobrien  cfun->eh->protect_list = TREE_CHAIN (cfun->eh->protect_list);
105590075Sobrien
105690075Sobrien  /* End all the exception regions.  */
105790075Sobrien  for (; t; t = TREE_CHAIN (t))
105890075Sobrien    expand_eh_region_end_cleanup (TREE_VALUE (t));
105950397Sobrien}
106050397Sobrien
106190075Sobrien
106290075Sobrien/* This section is for the exception handling specific optimization pass.  */
106350397Sobrien
106490075Sobrien/* Random access the exception region tree.  It's just as simple to
106590075Sobrien   collect the regions this way as in expand_eh_region_start, but
106690075Sobrien   without having to realloc memory.  */
106790075Sobrien
106890075Sobrienstatic void
106990075Sobriencollect_eh_region_array ()
107050397Sobrien{
107190075Sobrien  struct eh_region **array, *i;
107250397Sobrien
107390075Sobrien  i = cfun->eh->region_tree;
107490075Sobrien  if (! i)
107590075Sobrien    return;
107650397Sobrien
107790075Sobrien  array = xcalloc (cfun->eh->last_region_number + 1, sizeof (*array));
107890075Sobrien  cfun->eh->region_array = array;
107950397Sobrien
108090075Sobrien  while (1)
108190075Sobrien    {
108290075Sobrien      array[i->region_number] = i;
108350397Sobrien
108490075Sobrien      /* If there are sub-regions, process them.  */
108590075Sobrien      if (i->inner)
108690075Sobrien	i = i->inner;
108790075Sobrien      /* If there are peers, process them.  */
108890075Sobrien      else if (i->next_peer)
108990075Sobrien	i = i->next_peer;
109090075Sobrien      /* Otherwise, step back up the tree to the next peer.  */
109190075Sobrien      else
109290075Sobrien	{
109390075Sobrien	  do {
109490075Sobrien	    i = i->outer;
109590075Sobrien	    if (i == NULL)
109690075Sobrien	      return;
109790075Sobrien	  } while (i->next_peer == NULL);
109890075Sobrien	  i = i->next_peer;
109990075Sobrien	}
110090075Sobrien    }
110190075Sobrien}
110250397Sobrien
110390075Sobrienstatic void
110490075Sobrienresolve_fixup_regions ()
110550397Sobrien{
110690075Sobrien  int i, j, n = cfun->eh->last_region_number;
110750397Sobrien
110890075Sobrien  for (i = 1; i <= n; ++i)
110990075Sobrien    {
111090075Sobrien      struct eh_region *fixup = cfun->eh->region_array[i];
111190075Sobrien      struct eh_region *cleanup = 0;
111250397Sobrien
111390075Sobrien      if (! fixup || fixup->type != ERT_FIXUP)
111490075Sobrien	continue;
111550397Sobrien
111690075Sobrien      for (j = 1; j <= n; ++j)
111790075Sobrien	{
111890075Sobrien	  cleanup = cfun->eh->region_array[j];
111990075Sobrien	  if (cleanup->type == ERT_CLEANUP
112090075Sobrien	      && cleanup->u.cleanup.exp == fixup->u.fixup.cleanup_exp)
112190075Sobrien	    break;
112290075Sobrien	}
112390075Sobrien      if (j > n)
112490075Sobrien	abort ();
112590075Sobrien
112690075Sobrien      fixup->u.fixup.real_region = cleanup->outer;
112790075Sobrien    }
112850397Sobrien}
112950397Sobrien
113090075Sobrien/* Now that we've discovered what region actually encloses a fixup,
113190075Sobrien   we can shuffle pointers and remove them from the tree.  */
113250397Sobrien
113350397Sobrienstatic void
113490075Sobrienremove_fixup_regions ()
113550397Sobrien{
113690075Sobrien  int i;
113790075Sobrien  rtx insn, note;
113890075Sobrien  struct eh_region *fixup;
113990075Sobrien
114090075Sobrien  /* Walk the insn chain and adjust the REG_EH_REGION numbers
114190075Sobrien     for instructions referencing fixup regions.  This is only
114290075Sobrien     strictly necessary for fixup regions with no parent, but
114390075Sobrien     doesn't hurt to do it for all regions.  */
114490075Sobrien  for (insn = get_insns(); insn ; insn = NEXT_INSN (insn))
114590075Sobrien    if (INSN_P (insn)
114690075Sobrien	&& (note = find_reg_note (insn, REG_EH_REGION, NULL))
114790075Sobrien	&& INTVAL (XEXP (note, 0)) > 0
114890075Sobrien	&& (fixup = cfun->eh->region_array[INTVAL (XEXP (note, 0))])
114990075Sobrien	&& fixup->type == ERT_FIXUP)
115050397Sobrien      {
115190075Sobrien	if (fixup->u.fixup.real_region)
115290075Sobrien	  XEXP (note, 0) = GEN_INT (fixup->u.fixup.real_region->region_number);
115390075Sobrien	else
115490075Sobrien	  remove_note (insn, note);
115550397Sobrien      }
115650397Sobrien
115790075Sobrien  /* Remove the fixup regions from the tree.  */
115890075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
115990075Sobrien    {
116090075Sobrien      fixup = cfun->eh->region_array[i];
116190075Sobrien      if (! fixup)
116290075Sobrien	continue;
116350397Sobrien
116490075Sobrien      /* Allow GC to maybe free some memory.  */
116590075Sobrien      if (fixup->type == ERT_CLEANUP)
116690075Sobrien        fixup->u.cleanup.exp = NULL_TREE;
116750397Sobrien
116890075Sobrien      if (fixup->type != ERT_FIXUP)
116990075Sobrien	continue;
117050397Sobrien
117190075Sobrien      if (fixup->inner)
117290075Sobrien	{
117390075Sobrien	  struct eh_region *parent, *p, **pp;
117450397Sobrien
117590075Sobrien	  parent = fixup->u.fixup.real_region;
117652284Sobrien
117790075Sobrien	  /* Fix up the children's parent pointers; find the end of
117890075Sobrien	     the list.  */
117990075Sobrien	  for (p = fixup->inner; ; p = p->next_peer)
118090075Sobrien	    {
118190075Sobrien	      p->outer = parent;
118290075Sobrien	      if (! p->next_peer)
118390075Sobrien		break;
118490075Sobrien	    }
118550397Sobrien
118690075Sobrien	  /* In the tree of cleanups, only outer-inner ordering matters.
118790075Sobrien	     So link the children back in anywhere at the correct level.  */
118890075Sobrien	  if (parent)
118990075Sobrien	    pp = &parent->inner;
119090075Sobrien	  else
119190075Sobrien	    pp = &cfun->eh->region_tree;
119290075Sobrien	  p->next_peer = *pp;
119390075Sobrien	  *pp = fixup->inner;
119490075Sobrien	  fixup->inner = NULL;
119590075Sobrien	}
119690075Sobrien
119790075Sobrien      remove_eh_handler (fixup);
119850397Sobrien    }
119950397Sobrien}
120050397Sobrien
120190075Sobrien/* Remove all regions whose labels are not reachable from insns.  */
120252284Sobrien
120390075Sobrienstatic void
120490075Sobrienremove_unreachable_regions (insns)
120590075Sobrien     rtx insns;
120652284Sobrien{
120790075Sobrien  int i, *uid_region_num;
120890075Sobrien  bool *reachable;
120990075Sobrien  struct eh_region *r;
121090075Sobrien  rtx insn;
121152284Sobrien
121290075Sobrien  uid_region_num = xcalloc (get_max_uid (), sizeof(int));
121390075Sobrien  reachable = xcalloc (cfun->eh->last_region_number + 1, sizeof(bool));
121452284Sobrien
121590075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
121690075Sobrien    {
121790075Sobrien      r = cfun->eh->region_array[i];
121890075Sobrien      if (!r || r->region_number != i)
121990075Sobrien	continue;
122052284Sobrien
122190075Sobrien      if (r->resume)
122290075Sobrien        {
122390075Sobrien	  if (uid_region_num[INSN_UID (r->resume)])
122490075Sobrien	    abort ();
122590075Sobrien	  uid_region_num[INSN_UID (r->resume)] = i;
122690075Sobrien        }
122790075Sobrien      if (r->label)
122890075Sobrien        {
122990075Sobrien	  if (uid_region_num[INSN_UID (r->label)])
123090075Sobrien	    abort ();
123190075Sobrien	  uid_region_num[INSN_UID (r->label)] = i;
123290075Sobrien        }
123390075Sobrien      if (r->type == ERT_TRY && r->u.try.continue_label)
123490075Sobrien        {
123590075Sobrien	  if (uid_region_num[INSN_UID (r->u.try.continue_label)])
123690075Sobrien	    abort ();
123790075Sobrien	  uid_region_num[INSN_UID (r->u.try.continue_label)] = i;
123890075Sobrien        }
123952284Sobrien    }
124052284Sobrien
124190075Sobrien  for (insn = insns; insn; insn = NEXT_INSN (insn))
124290075Sobrien    reachable[uid_region_num[INSN_UID (insn)]] = true;
124350397Sobrien
124490075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
124550397Sobrien    {
124690075Sobrien      r = cfun->eh->region_array[i];
124790075Sobrien      if (r && r->region_number == i && !reachable[i])
124850397Sobrien	{
124990075Sobrien	  /* Don't remove ERT_THROW regions if their outer region
125090075Sobrien	     is reachable.  */
125190075Sobrien	  if (r->type == ERT_THROW
125290075Sobrien	      && r->outer
125390075Sobrien	      && reachable[r->outer->region_number])
125490075Sobrien	    continue;
125590075Sobrien
125690075Sobrien	  remove_eh_handler (r);
125750397Sobrien	}
125850397Sobrien    }
125990075Sobrien
126090075Sobrien  free (reachable);
126190075Sobrien  free (uid_region_num);
126250397Sobrien}
126350397Sobrien
126490075Sobrien/* Turn NOTE_INSN_EH_REGION notes into REG_EH_REGION notes for each
126590075Sobrien   can_throw instruction in the region.  */
126650397Sobrien
126790075Sobrienstatic void
126890075Sobrienconvert_from_eh_region_ranges_1 (pinsns, orig_sp, cur)
126990075Sobrien     rtx *pinsns;
127090075Sobrien     int *orig_sp;
127190075Sobrien     int cur;
127250397Sobrien{
127390075Sobrien  int *sp = orig_sp;
127490075Sobrien  rtx insn, next;
127550397Sobrien
127690075Sobrien  for (insn = *pinsns; insn ; insn = next)
127790075Sobrien    {
127890075Sobrien      next = NEXT_INSN (insn);
127990075Sobrien      if (GET_CODE (insn) == NOTE)
128090075Sobrien	{
128190075Sobrien	  int kind = NOTE_LINE_NUMBER (insn);
128290075Sobrien	  if (kind == NOTE_INSN_EH_REGION_BEG
128390075Sobrien	      || kind == NOTE_INSN_EH_REGION_END)
128490075Sobrien	    {
128590075Sobrien	      if (kind == NOTE_INSN_EH_REGION_BEG)
128690075Sobrien		{
128790075Sobrien		  struct eh_region *r;
128850397Sobrien
128990075Sobrien		  *sp++ = cur;
129090075Sobrien		  cur = NOTE_EH_HANDLER (insn);
129150397Sobrien
129290075Sobrien		  r = cfun->eh->region_array[cur];
129390075Sobrien		  if (r->type == ERT_FIXUP)
129490075Sobrien		    {
129590075Sobrien		      r = r->u.fixup.real_region;
129690075Sobrien		      cur = r ? r->region_number : 0;
129790075Sobrien		    }
129890075Sobrien		  else if (r->type == ERT_CATCH)
129990075Sobrien		    {
130090075Sobrien		      r = r->outer;
130190075Sobrien		      cur = r ? r->region_number : 0;
130290075Sobrien		    }
130390075Sobrien		}
130490075Sobrien	      else
130590075Sobrien		cur = *--sp;
130650397Sobrien
130790075Sobrien	      /* Removing the first insn of a CALL_PLACEHOLDER sequence
130890075Sobrien		 requires extra care to adjust sequence start.  */
130990075Sobrien	      if (insn == *pinsns)
131090075Sobrien		*pinsns = next;
131190075Sobrien	      remove_insn (insn);
131290075Sobrien	      continue;
131390075Sobrien	    }
131490075Sobrien	}
131590075Sobrien      else if (INSN_P (insn))
131690075Sobrien	{
131790075Sobrien	  if (cur > 0
131890075Sobrien	      && ! find_reg_note (insn, REG_EH_REGION, NULL_RTX)
131990075Sobrien	      /* Calls can always potentially throw exceptions, unless
132090075Sobrien		 they have a REG_EH_REGION note with a value of 0 or less.
132190075Sobrien		 Which should be the only possible kind so far.  */
132290075Sobrien	      && (GET_CODE (insn) == CALL_INSN
132390075Sobrien		  /* If we wanted exceptions for non-call insns, then
132490075Sobrien		     any may_trap_p instruction could throw.  */
132590075Sobrien		  || (flag_non_call_exceptions
132690075Sobrien		      && GET_CODE (PATTERN (insn)) != CLOBBER
132790075Sobrien		      && GET_CODE (PATTERN (insn)) != USE
132890075Sobrien		      && may_trap_p (PATTERN (insn)))))
132990075Sobrien	    {
133090075Sobrien	      REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION, GEN_INT (cur),
133190075Sobrien						  REG_NOTES (insn));
133290075Sobrien	    }
133350397Sobrien
133490075Sobrien	  if (GET_CODE (insn) == CALL_INSN
133590075Sobrien	      && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
133690075Sobrien	    {
133790075Sobrien	      convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 0),
133890075Sobrien					       sp, cur);
133990075Sobrien	      convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 1),
134090075Sobrien					       sp, cur);
134190075Sobrien	      convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 2),
134290075Sobrien					       sp, cur);
134390075Sobrien	    }
134490075Sobrien	}
134590075Sobrien    }
134650397Sobrien
134790075Sobrien  if (sp != orig_sp)
134890075Sobrien    abort ();
134950397Sobrien}
135050397Sobrien
135190075Sobrienvoid
135290075Sobrienconvert_from_eh_region_ranges ()
135350397Sobrien{
135490075Sobrien  int *stack;
135590075Sobrien  rtx insns;
135650397Sobrien
135790075Sobrien  collect_eh_region_array ();
135890075Sobrien  resolve_fixup_regions ();
135950397Sobrien
136090075Sobrien  stack = xmalloc (sizeof (int) * (cfun->eh->last_region_number + 1));
136190075Sobrien  insns = get_insns ();
136290075Sobrien  convert_from_eh_region_ranges_1 (&insns, stack, 0);
136390075Sobrien  free (stack);
136450397Sobrien
136590075Sobrien  remove_fixup_regions ();
136690075Sobrien  remove_unreachable_regions (insns);
136750397Sobrien}
136850397Sobrien
136990075Sobrienvoid
137090075Sobrienfind_exception_handler_labels ()
137190075Sobrien{
137290075Sobrien  rtx list = NULL_RTX;
137390075Sobrien  int i;
137450397Sobrien
137590075Sobrien  free_EXPR_LIST_list (&exception_handler_labels);
137650397Sobrien
137790075Sobrien  if (cfun->eh->region_tree == NULL)
137890075Sobrien    return;
137990075Sobrien
138090075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
138150397Sobrien    {
138290075Sobrien      struct eh_region *region = cfun->eh->region_array[i];
138390075Sobrien      rtx lab;
138450397Sobrien
138590075Sobrien      if (! region || region->region_number != i)
138690075Sobrien	continue;
138790075Sobrien      if (cfun->eh->built_landing_pads)
138890075Sobrien	lab = region->landing_pad;
138990075Sobrien      else
139090075Sobrien	lab = region->label;
139150397Sobrien
139290075Sobrien      if (lab)
139390075Sobrien	list = alloc_EXPR_LIST (0, lab, list);
139450397Sobrien    }
139590075Sobrien
139690075Sobrien  /* For sjlj exceptions, need the return label to remain live until
139790075Sobrien     after landing pad generation.  */
139890075Sobrien  if (USING_SJLJ_EXCEPTIONS && ! cfun->eh->built_landing_pads)
139990075Sobrien    list = alloc_EXPR_LIST (0, return_label, list);
140090075Sobrien
140190075Sobrien  exception_handler_labels = list;
140250397Sobrien}
140350397Sobrien
140490075Sobrien
140590075Sobrienstatic struct eh_region *
140690075Sobrienduplicate_eh_region_1 (o, map)
140790075Sobrien     struct eh_region *o;
140890075Sobrien     struct inline_remap *map;
140950397Sobrien{
141090075Sobrien  struct eh_region *n
141190075Sobrien    = (struct eh_region *) xcalloc (1, sizeof (struct eh_region));
141250397Sobrien
141390075Sobrien  n->region_number = o->region_number + cfun->eh->last_region_number;
141490075Sobrien  n->type = o->type;
141550397Sobrien
141690075Sobrien  switch (n->type)
141790075Sobrien    {
141890075Sobrien    case ERT_CLEANUP:
141990075Sobrien    case ERT_MUST_NOT_THROW:
142090075Sobrien      break;
142150397Sobrien
142290075Sobrien    case ERT_TRY:
142390075Sobrien      if (o->u.try.continue_label)
142490075Sobrien	n->u.try.continue_label
142590075Sobrien	  = get_label_from_map (map,
142690075Sobrien				CODE_LABEL_NUMBER (o->u.try.continue_label));
142790075Sobrien      break;
142850397Sobrien
142990075Sobrien    case ERT_CATCH:
143090075Sobrien      n->u.catch.type_list = o->u.catch.type_list;
143190075Sobrien      break;
143250397Sobrien
143390075Sobrien    case ERT_ALLOWED_EXCEPTIONS:
143490075Sobrien      n->u.allowed.type_list = o->u.allowed.type_list;
143590075Sobrien      break;
143650397Sobrien
143790075Sobrien    case ERT_THROW:
143890075Sobrien      n->u.throw.type = o->u.throw.type;
143950397Sobrien
144090075Sobrien    default:
144190075Sobrien      abort ();
144290075Sobrien    }
144350397Sobrien
144490075Sobrien  if (o->label)
144590075Sobrien    n->label = get_label_from_map (map, CODE_LABEL_NUMBER (o->label));
144690075Sobrien  if (o->resume)
144790075Sobrien    {
144890075Sobrien      n->resume = map->insn_map[INSN_UID (o->resume)];
144990075Sobrien      if (n->resume == NULL)
145090075Sobrien	abort ();
145190075Sobrien    }
145250397Sobrien
145390075Sobrien  return n;
145450397Sobrien}
145550397Sobrien
145650397Sobrienstatic void
145790075Sobrienduplicate_eh_region_2 (o, n_array)
145890075Sobrien     struct eh_region *o;
145990075Sobrien     struct eh_region **n_array;
146050397Sobrien{
146190075Sobrien  struct eh_region *n = n_array[o->region_number];
146250397Sobrien
146390075Sobrien  switch (n->type)
146490075Sobrien    {
146590075Sobrien    case ERT_TRY:
146690075Sobrien      n->u.try.catch = n_array[o->u.try.catch->region_number];
146790075Sobrien      n->u.try.last_catch = n_array[o->u.try.last_catch->region_number];
146890075Sobrien      break;
146950397Sobrien
147090075Sobrien    case ERT_CATCH:
147190075Sobrien      if (o->u.catch.next_catch)
147290075Sobrien        n->u.catch.next_catch = n_array[o->u.catch.next_catch->region_number];
147390075Sobrien      if (o->u.catch.prev_catch)
147490075Sobrien        n->u.catch.prev_catch = n_array[o->u.catch.prev_catch->region_number];
147590075Sobrien      break;
147650397Sobrien
147790075Sobrien    default:
147890075Sobrien      break;
147990075Sobrien    }
148090075Sobrien
148190075Sobrien  if (o->outer)
148290075Sobrien    n->outer = n_array[o->outer->region_number];
148390075Sobrien  if (o->inner)
148490075Sobrien    n->inner = n_array[o->inner->region_number];
148590075Sobrien  if (o->next_peer)
148690075Sobrien    n->next_peer = n_array[o->next_peer->region_number];
148790075Sobrien}
148890075Sobrien
148990075Sobrienint
149090075Sobrienduplicate_eh_regions (ifun, map)
149190075Sobrien     struct function *ifun;
149290075Sobrien     struct inline_remap *map;
149350397Sobrien{
149490075Sobrien  int ifun_last_region_number = ifun->eh->last_region_number;
149590075Sobrien  struct eh_region **n_array, *root, *cur;
149690075Sobrien  int i;
149750397Sobrien
149890075Sobrien  if (ifun_last_region_number == 0)
149990075Sobrien    return 0;
150050397Sobrien
150190075Sobrien  n_array = xcalloc (ifun_last_region_number + 1, sizeof (*n_array));
150250397Sobrien
150390075Sobrien  for (i = 1; i <= ifun_last_region_number; ++i)
150490075Sobrien    {
150590075Sobrien      cur = ifun->eh->region_array[i];
150690075Sobrien      if (!cur || cur->region_number != i)
150790075Sobrien	continue;
150890075Sobrien      n_array[i] = duplicate_eh_region_1 (cur, map);
150990075Sobrien    }
151090075Sobrien  for (i = 1; i <= ifun_last_region_number; ++i)
151190075Sobrien    {
151290075Sobrien      cur = ifun->eh->region_array[i];
151390075Sobrien      if (!cur || cur->region_number != i)
151490075Sobrien	continue;
151590075Sobrien      duplicate_eh_region_2 (cur, n_array);
151690075Sobrien    }
151750397Sobrien
151890075Sobrien  root = n_array[ifun->eh->region_tree->region_number];
151990075Sobrien  cur = cfun->eh->cur_region;
152090075Sobrien  if (cur)
152190075Sobrien    {
152290075Sobrien      struct eh_region *p = cur->inner;
152390075Sobrien      if (p)
152490075Sobrien	{
152590075Sobrien	  while (p->next_peer)
152690075Sobrien	    p = p->next_peer;
152790075Sobrien	  p->next_peer = root;
152890075Sobrien	}
152990075Sobrien      else
153090075Sobrien	cur->inner = root;
153150397Sobrien
153290075Sobrien      for (i = 1; i <= ifun_last_region_number; ++i)
153390075Sobrien	if (n_array[i] && n_array[i]->outer == NULL)
153490075Sobrien	  n_array[i]->outer = cur;
153590075Sobrien    }
153690075Sobrien  else
153790075Sobrien    {
153890075Sobrien      struct eh_region *p = cfun->eh->region_tree;
153990075Sobrien      if (p)
154090075Sobrien	{
154190075Sobrien	  while (p->next_peer)
154290075Sobrien	    p = p->next_peer;
154390075Sobrien	  p->next_peer = root;
154490075Sobrien	}
154590075Sobrien      else
154690075Sobrien	cfun->eh->region_tree = root;
154790075Sobrien    }
154850397Sobrien
154990075Sobrien  free (n_array);
155050397Sobrien
155190075Sobrien  i = cfun->eh->last_region_number;
155290075Sobrien  cfun->eh->last_region_number = i + ifun_last_region_number;
155390075Sobrien  return i;
155490075Sobrien}
155550397Sobrien
155690075Sobrien
155790075Sobrienstatic int
155890075Sobrient2r_eq (pentry, pdata)
155990075Sobrien     const PTR pentry;
156090075Sobrien     const PTR pdata;
156190075Sobrien{
156290075Sobrien  tree entry = (tree) pentry;
156390075Sobrien  tree data = (tree) pdata;
156450397Sobrien
156590075Sobrien  return TREE_PURPOSE (entry) == data;
156690075Sobrien}
156750397Sobrien
156890075Sobrienstatic hashval_t
156990075Sobrient2r_hash (pentry)
157090075Sobrien     const PTR pentry;
157190075Sobrien{
157290075Sobrien  tree entry = (tree) pentry;
157390075Sobrien  return TYPE_HASH (TREE_PURPOSE (entry));
157450397Sobrien}
157550397Sobrien
157690075Sobrienstatic int
157790075Sobrient2r_mark_1 (slot, data)
157890075Sobrien     PTR *slot;
157990075Sobrien     PTR data ATTRIBUTE_UNUSED;
158090075Sobrien{
158190075Sobrien  tree contents = (tree) *slot;
158290075Sobrien  ggc_mark_tree (contents);
158390075Sobrien  return 1;
158490075Sobrien}
158550397Sobrien
158650397Sobrienstatic void
158790075Sobrient2r_mark (addr)
158890075Sobrien     PTR addr;
158950397Sobrien{
159090075Sobrien  htab_traverse (*(htab_t *)addr, t2r_mark_1, NULL);
159190075Sobrien}
159250397Sobrien
159390075Sobrienstatic void
159490075Sobrienadd_type_for_runtime (type)
159590075Sobrien     tree type;
159690075Sobrien{
159790075Sobrien  tree *slot;
159850397Sobrien
159990075Sobrien  slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
160090075Sobrien					    TYPE_HASH (type), INSERT);
160190075Sobrien  if (*slot == NULL)
160290075Sobrien    {
160390075Sobrien      tree runtime = (*lang_eh_runtime_type) (type);
160490075Sobrien      *slot = tree_cons (type, runtime, NULL_TREE);
160590075Sobrien    }
160690075Sobrien}
160750397Sobrien
160890075Sobrienstatic tree
160990075Sobrienlookup_type_for_runtime (type)
161090075Sobrien     tree type;
161190075Sobrien{
161290075Sobrien  tree *slot;
161350397Sobrien
161490075Sobrien  slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
161590075Sobrien					    TYPE_HASH (type), NO_INSERT);
161650397Sobrien
161790075Sobrien  /* We should have always inserted the data earlier.  */
161890075Sobrien  return TREE_VALUE (*slot);
161990075Sobrien}
162050397Sobrien
162190075Sobrien
162290075Sobrien/* Represent an entry in @TTypes for either catch actions
162390075Sobrien   or exception filter actions.  */
162490075Sobrienstruct ttypes_filter
162590075Sobrien{
162690075Sobrien  tree t;
162790075Sobrien  int filter;
162890075Sobrien};
162950397Sobrien
163090075Sobrien/* Compare ENTRY (a ttypes_filter entry in the hash table) with DATA
163190075Sobrien   (a tree) for a @TTypes type node we are thinking about adding.  */
163250397Sobrien
163390075Sobrienstatic int
163490075Sobrienttypes_filter_eq (pentry, pdata)
163590075Sobrien     const PTR pentry;
163690075Sobrien     const PTR pdata;
163790075Sobrien{
163890075Sobrien  const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
163990075Sobrien  tree data = (tree) pdata;
164050397Sobrien
164190075Sobrien  return entry->t == data;
164250397Sobrien}
164350397Sobrien
164490075Sobrienstatic hashval_t
164590075Sobrienttypes_filter_hash (pentry)
164690075Sobrien     const PTR pentry;
164790075Sobrien{
164890075Sobrien  const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
164990075Sobrien  return TYPE_HASH (entry->t);
165090075Sobrien}
165150397Sobrien
165290075Sobrien/* Compare ENTRY with DATA (both struct ttypes_filter) for a @TTypes
165390075Sobrien   exception specification list we are thinking about adding.  */
165490075Sobrien/* ??? Currently we use the type lists in the order given.  Someone
165590075Sobrien   should put these in some canonical order.  */
165650397Sobrien
165790075Sobrienstatic int
165890075Sobrienehspec_filter_eq (pentry, pdata)
165990075Sobrien     const PTR pentry;
166090075Sobrien     const PTR pdata;
166150397Sobrien{
166290075Sobrien  const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
166390075Sobrien  const struct ttypes_filter *data = (const struct ttypes_filter *) pdata;
166450397Sobrien
166590075Sobrien  return type_list_equal (entry->t, data->t);
166690075Sobrien}
166750397Sobrien
166890075Sobrien/* Hash function for exception specification lists.  */
166950397Sobrien
167090075Sobrienstatic hashval_t
167190075Sobrienehspec_filter_hash (pentry)
167290075Sobrien     const PTR pentry;
167390075Sobrien{
167490075Sobrien  const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
167590075Sobrien  hashval_t h = 0;
167690075Sobrien  tree list;
167750397Sobrien
167890075Sobrien  for (list = entry->t; list ; list = TREE_CHAIN (list))
167990075Sobrien    h = (h << 5) + (h >> 27) + TYPE_HASH (TREE_VALUE (list));
168090075Sobrien  return h;
168150397Sobrien}
168250397Sobrien
168390075Sobrien/* Add TYPE to cfun->eh->ttype_data, using TYPES_HASH to speed
168490075Sobrien   up the search.  Return the filter value to be used.  */
168550397Sobrien
168690075Sobrienstatic int
168790075Sobrienadd_ttypes_entry (ttypes_hash, type)
168890075Sobrien     htab_t ttypes_hash;
168990075Sobrien     tree type;
169050397Sobrien{
169190075Sobrien  struct ttypes_filter **slot, *n;
169250397Sobrien
169390075Sobrien  slot = (struct ttypes_filter **)
169490075Sobrien    htab_find_slot_with_hash (ttypes_hash, type, TYPE_HASH (type), INSERT);
169550397Sobrien
169690075Sobrien  if ((n = *slot) == NULL)
169750397Sobrien    {
169890075Sobrien      /* Filter value is a 1 based table index.  */
169950397Sobrien
170090075Sobrien      n = (struct ttypes_filter *) xmalloc (sizeof (*n));
170190075Sobrien      n->t = type;
170290075Sobrien      n->filter = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) + 1;
170390075Sobrien      *slot = n;
170450397Sobrien
170590075Sobrien      VARRAY_PUSH_TREE (cfun->eh->ttype_data, type);
170650397Sobrien    }
170750397Sobrien
170890075Sobrien  return n->filter;
170950397Sobrien}
171050397Sobrien
171190075Sobrien/* Add LIST to cfun->eh->ehspec_data, using EHSPEC_HASH and TYPES_HASH
171290075Sobrien   to speed up the search.  Return the filter value to be used.  */
171350397Sobrien
171490075Sobrienstatic int
171590075Sobrienadd_ehspec_entry (ehspec_hash, ttypes_hash, list)
171690075Sobrien     htab_t ehspec_hash;
171790075Sobrien     htab_t ttypes_hash;
171890075Sobrien     tree list;
171950397Sobrien{
172090075Sobrien  struct ttypes_filter **slot, *n;
172190075Sobrien  struct ttypes_filter dummy;
172250397Sobrien
172390075Sobrien  dummy.t = list;
172490075Sobrien  slot = (struct ttypes_filter **)
172590075Sobrien    htab_find_slot (ehspec_hash, &dummy, INSERT);
172650397Sobrien
172790075Sobrien  if ((n = *slot) == NULL)
172890075Sobrien    {
172990075Sobrien      /* Filter value is a -1 based byte index into a uleb128 buffer.  */
173050397Sobrien
173190075Sobrien      n = (struct ttypes_filter *) xmalloc (sizeof (*n));
173290075Sobrien      n->t = list;
173390075Sobrien      n->filter = -(VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) + 1);
173490075Sobrien      *slot = n;
173550397Sobrien
173690075Sobrien      /* Look up each type in the list and encode its filter
173790075Sobrien	 value as a uleb128.  Terminate the list with 0.  */
173890075Sobrien      for (; list ; list = TREE_CHAIN (list))
173990075Sobrien	push_uleb128 (&cfun->eh->ehspec_data,
174090075Sobrien		      add_ttypes_entry (ttypes_hash, TREE_VALUE (list)));
174190075Sobrien      VARRAY_PUSH_UCHAR (cfun->eh->ehspec_data, 0);
174290075Sobrien    }
174390075Sobrien
174490075Sobrien  return n->filter;
174590075Sobrien}
174690075Sobrien
174790075Sobrien/* Generate the action filter values to be used for CATCH and
174890075Sobrien   ALLOWED_EXCEPTIONS regions.  When using dwarf2 exception regions,
174990075Sobrien   we use lots of landing pads, and so every type or list can share
175090075Sobrien   the same filter value, which saves table space.  */
175190075Sobrien
175290075Sobrienstatic void
175390075Sobrienassign_filter_values ()
175450397Sobrien{
175590075Sobrien  int i;
175690075Sobrien  htab_t ttypes, ehspec;
175750397Sobrien
175890075Sobrien  VARRAY_TREE_INIT (cfun->eh->ttype_data, 16, "ttype_data");
175990075Sobrien  VARRAY_UCHAR_INIT (cfun->eh->ehspec_data, 64, "ehspec_data");
176050397Sobrien
176190075Sobrien  ttypes = htab_create (31, ttypes_filter_hash, ttypes_filter_eq, free);
176290075Sobrien  ehspec = htab_create (31, ehspec_filter_hash, ehspec_filter_eq, free);
176350397Sobrien
176490075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
176550397Sobrien    {
176690075Sobrien      struct eh_region *r = cfun->eh->region_array[i];
176750397Sobrien
176890075Sobrien      /* Mind we don't process a region more than once.  */
176990075Sobrien      if (!r || r->region_number != i)
177090075Sobrien	continue;
177150397Sobrien
177290075Sobrien      switch (r->type)
177390075Sobrien	{
177490075Sobrien	case ERT_CATCH:
177590075Sobrien	  /* Whatever type_list is (NULL or true list), we build a list
177690075Sobrien	     of filters for the region.  */
177790075Sobrien	  r->u.catch.filter_list = NULL_TREE;
177850397Sobrien
177990075Sobrien	  if (r->u.catch.type_list != NULL)
178090075Sobrien	    {
178190075Sobrien	      /* Get a filter value for each of the types caught and store
178290075Sobrien		 them in the region's dedicated list.  */
178390075Sobrien	      tree tp_node = r->u.catch.type_list;
178450397Sobrien
178590075Sobrien	      for (;tp_node; tp_node = TREE_CHAIN (tp_node))
178690075Sobrien		{
178790075Sobrien		  int flt = add_ttypes_entry (ttypes, TREE_VALUE (tp_node));
178890075Sobrien		  tree flt_node = build_int_2 (flt, 0);
178950397Sobrien
179090075Sobrien		  r->u.catch.filter_list
179190075Sobrien		    = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list);
179290075Sobrien		}
179390075Sobrien	    }
179490075Sobrien	  else
179590075Sobrien	    {
179690075Sobrien	      /* Get a filter value for the NULL list also since it will need
179790075Sobrien		 an action record anyway.  */
179890075Sobrien	      int flt = add_ttypes_entry (ttypes, NULL);
179990075Sobrien	      tree flt_node = build_int_2 (flt, 0);
180050397Sobrien
180190075Sobrien	      r->u.catch.filter_list
180290075Sobrien		= tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list);
180390075Sobrien	    }
180450397Sobrien
180590075Sobrien	  break;
180650397Sobrien
180790075Sobrien	case ERT_ALLOWED_EXCEPTIONS:
180890075Sobrien	  r->u.allowed.filter
180990075Sobrien	    = add_ehspec_entry (ehspec, ttypes, r->u.allowed.type_list);
181090075Sobrien	  break;
181150397Sobrien
181290075Sobrien	default:
181390075Sobrien	  break;
181490075Sobrien	}
181550397Sobrien    }
181690075Sobrien
181790075Sobrien  htab_delete (ttypes);
181890075Sobrien  htab_delete (ehspec);
181950397Sobrien}
182050397Sobrien
182190075Sobrienstatic void
182290075Sobrienbuild_post_landing_pads ()
182350397Sobrien{
182490075Sobrien  int i;
182550397Sobrien
182690075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
182790075Sobrien    {
182890075Sobrien      struct eh_region *region = cfun->eh->region_array[i];
182990075Sobrien      rtx seq;
183050397Sobrien
183190075Sobrien      /* Mind we don't process a region more than once.  */
183290075Sobrien      if (!region || region->region_number != i)
183390075Sobrien	continue;
183450397Sobrien
183590075Sobrien      switch (region->type)
183690075Sobrien	{
183790075Sobrien	case ERT_TRY:
183890075Sobrien	  /* ??? Collect the set of all non-overlapping catch handlers
183990075Sobrien	       all the way up the chain until blocked by a cleanup.  */
184090075Sobrien	  /* ??? Outer try regions can share landing pads with inner
184190075Sobrien	     try regions if the types are completely non-overlapping,
184290075Sobrien	     and there are no intervening cleanups.  */
184350397Sobrien
184490075Sobrien	  region->post_landing_pad = gen_label_rtx ();
184550397Sobrien
184690075Sobrien	  start_sequence ();
184750397Sobrien
184890075Sobrien	  emit_label (region->post_landing_pad);
184950397Sobrien
185090075Sobrien	  /* ??? It is mighty inconvenient to call back into the
185190075Sobrien	     switch statement generation code in expand_end_case.
185290075Sobrien	     Rapid prototyping sez a sequence of ifs.  */
185390075Sobrien	  {
185490075Sobrien	    struct eh_region *c;
185590075Sobrien	    for (c = region->u.try.catch; c ; c = c->u.catch.next_catch)
185690075Sobrien	      {
185790075Sobrien		/* ??? _Unwind_ForcedUnwind wants no match here.  */
185890075Sobrien		if (c->u.catch.type_list == NULL)
185990075Sobrien		  emit_jump (c->label);
186090075Sobrien		else
186190075Sobrien		  {
186290075Sobrien		    /* Need for one cmp/jump per type caught. Each type
186390075Sobrien		       list entry has a matching entry in the filter list
186490075Sobrien		       (see assign_filter_values).  */
186590075Sobrien		    tree tp_node = c->u.catch.type_list;
186690075Sobrien		    tree flt_node = c->u.catch.filter_list;
186750397Sobrien
186890075Sobrien		    for (; tp_node; )
186990075Sobrien		      {
187090075Sobrien			emit_cmp_and_jump_insns
187190075Sobrien			  (cfun->eh->filter,
187290075Sobrien			   GEN_INT (tree_low_cst (TREE_VALUE (flt_node), 0)),
187390075Sobrien			   EQ, NULL_RTX, word_mode, 0, c->label);
187450397Sobrien
187590075Sobrien			tp_node = TREE_CHAIN (tp_node);
187690075Sobrien			flt_node = TREE_CHAIN (flt_node);
187790075Sobrien		      }
187890075Sobrien		  }
187990075Sobrien	      }
188090075Sobrien	  }
188150397Sobrien
188290075Sobrien	  /* We delay the generation of the _Unwind_Resume until we generate
188390075Sobrien	     landing pads.  We emit a marker here so as to get good control
188490075Sobrien	     flow data in the meantime.  */
188590075Sobrien	  region->resume
188690075Sobrien	    = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
188790075Sobrien	  emit_barrier ();
188850397Sobrien
188990075Sobrien	  seq = get_insns ();
189090075Sobrien	  end_sequence ();
189150397Sobrien
189290075Sobrien	  emit_insns_before (seq, region->u.try.catch->label);
189390075Sobrien	  break;
189450397Sobrien
189590075Sobrien	case ERT_ALLOWED_EXCEPTIONS:
189690075Sobrien	  region->post_landing_pad = gen_label_rtx ();
189750397Sobrien
189890075Sobrien	  start_sequence ();
189950397Sobrien
190090075Sobrien	  emit_label (region->post_landing_pad);
190150397Sobrien
190290075Sobrien	  emit_cmp_and_jump_insns (cfun->eh->filter,
190390075Sobrien				   GEN_INT (region->u.allowed.filter),
190490075Sobrien				   EQ, NULL_RTX, word_mode, 0, region->label);
190550397Sobrien
190690075Sobrien	  /* We delay the generation of the _Unwind_Resume until we generate
190790075Sobrien	     landing pads.  We emit a marker here so as to get good control
190890075Sobrien	     flow data in the meantime.  */
190990075Sobrien	  region->resume
191090075Sobrien	    = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
191190075Sobrien	  emit_barrier ();
191250397Sobrien
191390075Sobrien	  seq = get_insns ();
191490075Sobrien	  end_sequence ();
191590075Sobrien
191690075Sobrien	  emit_insns_before (seq, region->label);
191790075Sobrien	  break;
191890075Sobrien
191990075Sobrien	case ERT_CLEANUP:
192090075Sobrien	case ERT_MUST_NOT_THROW:
192190075Sobrien	  region->post_landing_pad = region->label;
192290075Sobrien	  break;
192390075Sobrien
192490075Sobrien	case ERT_CATCH:
192590075Sobrien	case ERT_THROW:
192690075Sobrien	  /* Nothing to do.  */
192790075Sobrien	  break;
192890075Sobrien
192990075Sobrien	default:
193090075Sobrien	  abort ();
193190075Sobrien	}
193290075Sobrien    }
193350397Sobrien}
193450397Sobrien
193590075Sobrien/* Replace RESX patterns with jumps to the next handler if any, or calls to
193690075Sobrien   _Unwind_Resume otherwise.  */
193750397Sobrien
193890075Sobrienstatic void
193990075Sobrienconnect_post_landing_pads ()
194050397Sobrien{
194190075Sobrien  int i;
194250397Sobrien
194390075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
194450397Sobrien    {
194590075Sobrien      struct eh_region *region = cfun->eh->region_array[i];
194690075Sobrien      struct eh_region *outer;
194790075Sobrien      rtx seq;
194850397Sobrien
194990075Sobrien      /* Mind we don't process a region more than once.  */
195090075Sobrien      if (!region || region->region_number != i)
195190075Sobrien	continue;
195250397Sobrien
195390075Sobrien      /* If there is no RESX, or it has been deleted by flow, there's
195490075Sobrien	 nothing to fix up.  */
195590075Sobrien      if (! region->resume || INSN_DELETED_P (region->resume))
195690075Sobrien	continue;
195750397Sobrien
195890075Sobrien      /* Search for another landing pad in this function.  */
195990075Sobrien      for (outer = region->outer; outer ; outer = outer->outer)
196090075Sobrien	if (outer->post_landing_pad)
196190075Sobrien	  break;
196250397Sobrien
196390075Sobrien      start_sequence ();
196450397Sobrien
196590075Sobrien      if (outer)
196690075Sobrien	emit_jump (outer->post_landing_pad);
196790075Sobrien      else
196890075Sobrien	emit_library_call (unwind_resume_libfunc, LCT_THROW,
196990075Sobrien			   VOIDmode, 1, cfun->eh->exc_ptr, Pmode);
197050397Sobrien
197190075Sobrien      seq = get_insns ();
197290075Sobrien      end_sequence ();
197390075Sobrien      emit_insns_before (seq, region->resume);
197490075Sobrien      delete_insn (region->resume);
197550397Sobrien    }
197650397Sobrien}
197750397Sobrien
197890075Sobrien
197990075Sobrienstatic void
198090075Sobriendw2_build_landing_pads ()
198150397Sobrien{
198290075Sobrien  int i;
198390075Sobrien  unsigned int j;
198450397Sobrien
198590075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
198690075Sobrien    {
198790075Sobrien      struct eh_region *region = cfun->eh->region_array[i];
198890075Sobrien      rtx seq;
198990075Sobrien      bool clobbers_hard_regs = false;
199050397Sobrien
199190075Sobrien      /* Mind we don't process a region more than once.  */
199290075Sobrien      if (!region || region->region_number != i)
199390075Sobrien	continue;
199450397Sobrien
199590075Sobrien      if (region->type != ERT_CLEANUP
199690075Sobrien	  && region->type != ERT_TRY
199790075Sobrien	  && region->type != ERT_ALLOWED_EXCEPTIONS)
199890075Sobrien	continue;
199950397Sobrien
200090075Sobrien      start_sequence ();
200150397Sobrien
200290075Sobrien      region->landing_pad = gen_label_rtx ();
200390075Sobrien      emit_label (region->landing_pad);
200450397Sobrien
200590075Sobrien#ifdef HAVE_exception_receiver
200690075Sobrien      if (HAVE_exception_receiver)
200790075Sobrien	emit_insn (gen_exception_receiver ());
200890075Sobrien      else
200990075Sobrien#endif
201090075Sobrien#ifdef HAVE_nonlocal_goto_receiver
201190075Sobrien	if (HAVE_nonlocal_goto_receiver)
201290075Sobrien	  emit_insn (gen_nonlocal_goto_receiver ());
201390075Sobrien	else
201490075Sobrien#endif
201590075Sobrien	  { /* Nothing */ }
201650397Sobrien
201790075Sobrien      /* If the eh_return data registers are call-saved, then we
201890075Sobrien	 won't have considered them clobbered from the call that
201990075Sobrien	 threw.  Kill them now.  */
202090075Sobrien      for (j = 0; ; ++j)
202190075Sobrien	{
202290075Sobrien	  unsigned r = EH_RETURN_DATA_REGNO (j);
202390075Sobrien	  if (r == INVALID_REGNUM)
202490075Sobrien	    break;
202590075Sobrien	  if (! call_used_regs[r])
202690075Sobrien	    {
202790075Sobrien	      emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, r)));
202890075Sobrien	      clobbers_hard_regs = true;
202990075Sobrien	    }
203090075Sobrien	}
203152284Sobrien
203290075Sobrien      if (clobbers_hard_regs)
203390075Sobrien	{
203490075Sobrien	  /* @@@ This is a kludge.  Not all machine descriptions define a
203590075Sobrien	     blockage insn, but we must not allow the code we just generated
203690075Sobrien	     to be reordered by scheduling.  So emit an ASM_INPUT to act as
203790075Sobrien	     blockage insn.  */
203890075Sobrien	  emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
203990075Sobrien	}
204052284Sobrien
204190075Sobrien      emit_move_insn (cfun->eh->exc_ptr,
204290075Sobrien		      gen_rtx_REG (Pmode, EH_RETURN_DATA_REGNO (0)));
204390075Sobrien      emit_move_insn (cfun->eh->filter,
204490075Sobrien		      gen_rtx_REG (word_mode, EH_RETURN_DATA_REGNO (1)));
204552284Sobrien
204690075Sobrien      seq = get_insns ();
204790075Sobrien      end_sequence ();
204852284Sobrien
204990075Sobrien      emit_insns_before (seq, region->post_landing_pad);
205052284Sobrien    }
205150397Sobrien}
205250397Sobrien
205390075Sobrien
205490075Sobrienstruct sjlj_lp_info
205590075Sobrien{
205690075Sobrien  int directly_reachable;
205790075Sobrien  int action_index;
205890075Sobrien  int dispatch_index;
205990075Sobrien  int call_site_index;
206090075Sobrien};
206152284Sobrien
206290075Sobrienstatic bool
206390075Sobriensjlj_find_directly_reachable_regions (lp_info)
206490075Sobrien     struct sjlj_lp_info *lp_info;
206552284Sobrien{
206690075Sobrien  rtx insn;
206790075Sobrien  bool found_one = false;
206852284Sobrien
206990075Sobrien  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
207052284Sobrien    {
207190075Sobrien      struct eh_region *region;
207290075Sobrien      enum reachable_code rc;
207390075Sobrien      tree type_thrown;
207490075Sobrien      rtx note;
207590075Sobrien
207690075Sobrien      if (! INSN_P (insn))
207790075Sobrien	continue;
207890075Sobrien
207990075Sobrien      note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
208090075Sobrien      if (!note || INTVAL (XEXP (note, 0)) <= 0)
208190075Sobrien	continue;
208290075Sobrien
208390075Sobrien      region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
208490075Sobrien
208590075Sobrien      type_thrown = NULL_TREE;
208690075Sobrien      if (region->type == ERT_THROW)
208790075Sobrien	{
208890075Sobrien	  type_thrown = region->u.throw.type;
208990075Sobrien	  region = region->outer;
209090075Sobrien	}
209190075Sobrien
209290075Sobrien      /* Find the first containing region that might handle the exception.
209390075Sobrien	 That's the landing pad to which we will transfer control.  */
209490075Sobrien      rc = RNL_NOT_CAUGHT;
209590075Sobrien      for (; region; region = region->outer)
209690075Sobrien	{
209790075Sobrien	  rc = reachable_next_level (region, type_thrown, 0);
209890075Sobrien	  if (rc != RNL_NOT_CAUGHT)
209990075Sobrien	    break;
210090075Sobrien	}
210190075Sobrien      if (rc == RNL_MAYBE_CAUGHT || rc == RNL_CAUGHT)
210290075Sobrien	{
210390075Sobrien	  lp_info[region->region_number].directly_reachable = 1;
210490075Sobrien	  found_one = true;
210590075Sobrien	}
210652284Sobrien    }
210752284Sobrien
210890075Sobrien  return found_one;
210952284Sobrien}
211052284Sobrien
211190075Sobrienstatic void
211290075Sobriensjlj_assign_call_site_values (dispatch_label, lp_info)
211390075Sobrien     rtx dispatch_label;
211490075Sobrien     struct sjlj_lp_info *lp_info;
211590075Sobrien{
211690075Sobrien  htab_t ar_hash;
211790075Sobrien  int i, index;
211850397Sobrien
211990075Sobrien  /* First task: build the action table.  */
212050397Sobrien
212190075Sobrien  VARRAY_UCHAR_INIT (cfun->eh->action_record_data, 64, "action_record_data");
212290075Sobrien  ar_hash = htab_create (31, action_record_hash, action_record_eq, free);
212350397Sobrien
212490075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
212590075Sobrien    if (lp_info[i].directly_reachable)
212690075Sobrien      {
212790075Sobrien	struct eh_region *r = cfun->eh->region_array[i];
212890075Sobrien	r->landing_pad = dispatch_label;
212990075Sobrien	lp_info[i].action_index = collect_one_action_chain (ar_hash, r);
213090075Sobrien	if (lp_info[i].action_index != -1)
213190075Sobrien	  cfun->uses_eh_lsda = 1;
213290075Sobrien      }
213350397Sobrien
213490075Sobrien  htab_delete (ar_hash);
213550397Sobrien
213690075Sobrien  /* Next: assign dispatch values.  In dwarf2 terms, this would be the
213790075Sobrien     landing pad label for the region.  For sjlj though, there is one
213890075Sobrien     common landing pad from which we dispatch to the post-landing pads.
213950397Sobrien
214090075Sobrien     A region receives a dispatch index if it is directly reachable
214190075Sobrien     and requires in-function processing.  Regions that share post-landing
214290075Sobrien     pads may share dispatch indices.  */
214390075Sobrien  /* ??? Post-landing pad sharing doesn't actually happen at the moment
214490075Sobrien     (see build_post_landing_pads) so we don't bother checking for it.  */
214550397Sobrien
214690075Sobrien  index = 0;
214790075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
214890075Sobrien    if (lp_info[i].directly_reachable)
214990075Sobrien      lp_info[i].dispatch_index = index++;
215050397Sobrien
215190075Sobrien  /* Finally: assign call-site values.  If dwarf2 terms, this would be
215290075Sobrien     the region number assigned by convert_to_eh_region_ranges, but
215390075Sobrien     handles no-action and must-not-throw differently.  */
215450397Sobrien
215590075Sobrien  call_site_base = 1;
215690075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
215790075Sobrien    if (lp_info[i].directly_reachable)
215890075Sobrien      {
215990075Sobrien	int action = lp_info[i].action_index;
216090075Sobrien
216190075Sobrien	/* Map must-not-throw to otherwise unused call-site index 0.  */
216290075Sobrien	if (action == -2)
216390075Sobrien	  index = 0;
216490075Sobrien	/* Map no-action to otherwise unused call-site index -1.  */
216590075Sobrien	else if (action == -1)
216690075Sobrien	  index = -1;
216790075Sobrien	/* Otherwise, look it up in the table.  */
216890075Sobrien	else
216990075Sobrien	  index = add_call_site (GEN_INT (lp_info[i].dispatch_index), action);
217090075Sobrien
217190075Sobrien	lp_info[i].call_site_index = index;
217290075Sobrien      }
217390075Sobrien}
217490075Sobrien
217590075Sobrienstatic void
217690075Sobriensjlj_mark_call_sites (lp_info)
217790075Sobrien     struct sjlj_lp_info *lp_info;
217890075Sobrien{
217990075Sobrien  int last_call_site = -2;
218090075Sobrien  rtx insn, mem;
218190075Sobrien
218290075Sobrien  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
218350397Sobrien    {
218490075Sobrien      struct eh_region *region;
218590075Sobrien      int this_call_site;
218690075Sobrien      rtx note, before, p;
218750397Sobrien
218890075Sobrien      /* Reset value tracking at extended basic block boundaries.  */
218990075Sobrien      if (GET_CODE (insn) == CODE_LABEL)
219090075Sobrien	last_call_site = -2;
219150397Sobrien
219290075Sobrien      if (! INSN_P (insn))
219390075Sobrien	continue;
219450397Sobrien
219590075Sobrien      note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
219690075Sobrien      if (!note)
219790075Sobrien	{
219890075Sobrien	  /* Calls (and trapping insns) without notes are outside any
219990075Sobrien	     exception handling region in this function.  Mark them as
220090075Sobrien	     no action.  */
220190075Sobrien	  if (GET_CODE (insn) == CALL_INSN
220290075Sobrien	      || (flag_non_call_exceptions
220390075Sobrien		  && may_trap_p (PATTERN (insn))))
220490075Sobrien	    this_call_site = -1;
220590075Sobrien	  else
220690075Sobrien	    continue;
220790075Sobrien	}
220890075Sobrien      else
220990075Sobrien	{
221090075Sobrien	  /* Calls that are known to not throw need not be marked.  */
221190075Sobrien	  if (INTVAL (XEXP (note, 0)) <= 0)
221290075Sobrien	    continue;
221350397Sobrien
221490075Sobrien	  region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
221590075Sobrien	  this_call_site = lp_info[region->region_number].call_site_index;
221690075Sobrien	}
221750397Sobrien
221890075Sobrien      if (this_call_site == last_call_site)
221990075Sobrien	continue;
222050397Sobrien
222190075Sobrien      /* Don't separate a call from it's argument loads.  */
222290075Sobrien      before = insn;
222390075Sobrien      if (GET_CODE (insn) == CALL_INSN)
222490075Sobrien         before = find_first_parameter_load (insn, NULL_RTX);
222550397Sobrien
222690075Sobrien      start_sequence ();
222790075Sobrien      mem = adjust_address (cfun->eh->sjlj_fc, TYPE_MODE (integer_type_node),
222890075Sobrien			    sjlj_fc_call_site_ofs);
222990075Sobrien      emit_move_insn (mem, GEN_INT (this_call_site));
223090075Sobrien      p = get_insns ();
223190075Sobrien      end_sequence ();
223250397Sobrien
223390075Sobrien      emit_insns_before (p, before);
223490075Sobrien      last_call_site = this_call_site;
223550397Sobrien    }
223650397Sobrien}
223750397Sobrien
223890075Sobrien/* Construct the SjLj_Function_Context.  */
223950397Sobrien
224090075Sobrienstatic void
224190075Sobriensjlj_emit_function_enter (dispatch_label)
224290075Sobrien     rtx dispatch_label;
224350397Sobrien{
224490075Sobrien  rtx fn_begin, fc, mem, seq;
224550397Sobrien
224690075Sobrien  fc = cfun->eh->sjlj_fc;
224750397Sobrien
224890075Sobrien  start_sequence ();
224950397Sobrien
225090075Sobrien  /* We're storing this libcall's address into memory instead of
225190075Sobrien     calling it directly.  Thus, we must call assemble_external_libcall
225290075Sobrien     here, as we can not depend on emit_library_call to do it for us.  */
225390075Sobrien  assemble_external_libcall (eh_personality_libfunc);
225490075Sobrien  mem = adjust_address (fc, Pmode, sjlj_fc_personality_ofs);
225590075Sobrien  emit_move_insn (mem, eh_personality_libfunc);
225690075Sobrien
225790075Sobrien  mem = adjust_address (fc, Pmode, sjlj_fc_lsda_ofs);
225890075Sobrien  if (cfun->uses_eh_lsda)
225950397Sobrien    {
226090075Sobrien      char buf[20];
226190075Sobrien      ASM_GENERATE_INTERNAL_LABEL (buf, "LLSDA", sjlj_funcdef_number);
226290075Sobrien      emit_move_insn (mem, gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)));
226350397Sobrien    }
226490075Sobrien  else
226590075Sobrien    emit_move_insn (mem, const0_rtx);
226650397Sobrien
226790075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP
226890075Sobrien  {
226990075Sobrien    rtx x, note;
227090075Sobrien    x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_RETURNS_TWICE,
227190075Sobrien				 TYPE_MODE (integer_type_node), 1,
227290075Sobrien				 plus_constant (XEXP (fc, 0),
227390075Sobrien						sjlj_fc_jbuf_ofs), Pmode);
227450397Sobrien
227590075Sobrien    note = emit_note (NULL, NOTE_INSN_EXPECTED_VALUE);
227690075Sobrien    NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, x, const0_rtx);
227750397Sobrien
227890075Sobrien    emit_cmp_and_jump_insns (x, const0_rtx, NE, 0,
227990075Sobrien			     TYPE_MODE (integer_type_node), 0, dispatch_label);
228090075Sobrien  }
228190075Sobrien#else
228290075Sobrien  expand_builtin_setjmp_setup (plus_constant (XEXP (fc, 0), sjlj_fc_jbuf_ofs),
228390075Sobrien			       dispatch_label);
228490075Sobrien#endif
228550397Sobrien
228690075Sobrien  emit_library_call (unwind_sjlj_register_libfunc, LCT_NORMAL, VOIDmode,
228790075Sobrien		     1, XEXP (fc, 0), Pmode);
228890075Sobrien
228990075Sobrien  seq = get_insns ();
229050397Sobrien  end_sequence ();
229150397Sobrien
229290075Sobrien  /* ??? Instead of doing this at the beginning of the function,
229390075Sobrien     do this in a block that is at loop level 0 and dominates all
229490075Sobrien     can_throw_internal instructions.  */
229550397Sobrien
229690075Sobrien  for (fn_begin = get_insns (); ; fn_begin = NEXT_INSN (fn_begin))
229790075Sobrien    if (GET_CODE (fn_begin) == NOTE
229890075Sobrien	&& NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG)
229990075Sobrien      break;
230090075Sobrien  emit_insns_after (seq, fn_begin);
230150397Sobrien}
230250397Sobrien
230390075Sobrien/* Call back from expand_function_end to know where we should put
230490075Sobrien   the call to unwind_sjlj_unregister_libfunc if needed.  */
230550397Sobrien
230650397Sobrienvoid
230790075Sobriensjlj_emit_function_exit_after (after)
230890075Sobrien     rtx after;
230950397Sobrien{
231090075Sobrien  cfun->eh->sjlj_exit_after = after;
231150397Sobrien}
231250397Sobrien
231390075Sobrienstatic void
231490075Sobriensjlj_emit_function_exit ()
231550397Sobrien{
231690075Sobrien  rtx seq;
231750397Sobrien
231890075Sobrien  start_sequence ();
231950397Sobrien
232090075Sobrien  emit_library_call (unwind_sjlj_unregister_libfunc, LCT_NORMAL, VOIDmode,
232190075Sobrien		     1, XEXP (cfun->eh->sjlj_fc, 0), Pmode);
232250397Sobrien
232390075Sobrien  seq = get_insns ();
232490075Sobrien  end_sequence ();
232550397Sobrien
232690075Sobrien  /* ??? Really this can be done in any block at loop level 0 that
232790075Sobrien     post-dominates all can_throw_internal instructions.  This is
232890075Sobrien     the last possible moment.  */
232950397Sobrien
233090075Sobrien  emit_insns_after (seq, cfun->eh->sjlj_exit_after);
233190075Sobrien}
233250397Sobrien
233390075Sobrienstatic void
233490075Sobriensjlj_emit_dispatch_table (dispatch_label, lp_info)
233590075Sobrien     rtx dispatch_label;
233690075Sobrien     struct sjlj_lp_info *lp_info;
233790075Sobrien{
233890075Sobrien  int i, first_reachable;
233990075Sobrien  rtx mem, dispatch, seq, fc;
234050397Sobrien
234190075Sobrien  fc = cfun->eh->sjlj_fc;
234250397Sobrien
234390075Sobrien  start_sequence ();
234450397Sobrien
234590075Sobrien  emit_label (dispatch_label);
234650397Sobrien
234790075Sobrien#ifndef DONT_USE_BUILTIN_SETJMP
234890075Sobrien  expand_builtin_setjmp_receiver (dispatch_label);
234990075Sobrien#endif
235050397Sobrien
235190075Sobrien  /* Load up dispatch index, exc_ptr and filter values from the
235290075Sobrien     function context.  */
235390075Sobrien  mem = adjust_address (fc, TYPE_MODE (integer_type_node),
235490075Sobrien			sjlj_fc_call_site_ofs);
235590075Sobrien  dispatch = copy_to_reg (mem);
235650397Sobrien
235790075Sobrien  mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs);
235890075Sobrien  if (word_mode != Pmode)
235950397Sobrien    {
236090075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED
236190075Sobrien      mem = convert_memory_address (Pmode, mem);
236290075Sobrien#else
236390075Sobrien      mem = convert_to_mode (Pmode, mem, 0);
236490075Sobrien#endif
236590075Sobrien    }
236690075Sobrien  emit_move_insn (cfun->eh->exc_ptr, mem);
236750397Sobrien
236890075Sobrien  mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs + UNITS_PER_WORD);
236990075Sobrien  emit_move_insn (cfun->eh->filter, mem);
237050397Sobrien
237190075Sobrien  /* Jump to one of the directly reachable regions.  */
237290075Sobrien  /* ??? This really ought to be using a switch statement.  */
237390075Sobrien
237490075Sobrien  first_reachable = 0;
237590075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
237690075Sobrien    {
237790075Sobrien      if (! lp_info[i].directly_reachable)
237890075Sobrien	continue;
237990075Sobrien
238090075Sobrien      if (! first_reachable)
238150397Sobrien	{
238290075Sobrien	  first_reachable = i;
238390075Sobrien	  continue;
238450397Sobrien	}
238590075Sobrien
238690075Sobrien      emit_cmp_and_jump_insns (dispatch, GEN_INT (lp_info[i].dispatch_index),
238790075Sobrien			       EQ, NULL_RTX, TYPE_MODE (integer_type_node), 0,
238890075Sobrien			       cfun->eh->region_array[i]->post_landing_pad);
238950397Sobrien    }
239050397Sobrien
239190075Sobrien  seq = get_insns ();
239290075Sobrien  end_sequence ();
239350397Sobrien
239490075Sobrien  emit_insns_before (seq, (cfun->eh->region_array[first_reachable]
239590075Sobrien			   ->post_landing_pad));
239650397Sobrien}
239750397Sobrien
239850397Sobrienstatic void
239990075Sobriensjlj_build_landing_pads ()
240050397Sobrien{
240190075Sobrien  struct sjlj_lp_info *lp_info;
240250397Sobrien
240390075Sobrien  lp_info = (struct sjlj_lp_info *) xcalloc (cfun->eh->last_region_number + 1,
240490075Sobrien					     sizeof (struct sjlj_lp_info));
240550397Sobrien
240690075Sobrien  if (sjlj_find_directly_reachable_regions (lp_info))
240750397Sobrien    {
240890075Sobrien      rtx dispatch_label = gen_label_rtx ();
240952284Sobrien
241090075Sobrien      cfun->eh->sjlj_fc
241190075Sobrien	= assign_stack_local (TYPE_MODE (sjlj_fc_type_node),
241290075Sobrien			      int_size_in_bytes (sjlj_fc_type_node),
241390075Sobrien			      TYPE_ALIGN (sjlj_fc_type_node));
241450397Sobrien
241590075Sobrien      sjlj_assign_call_site_values (dispatch_label, lp_info);
241690075Sobrien      sjlj_mark_call_sites (lp_info);
241750397Sobrien
241890075Sobrien      sjlj_emit_function_enter (dispatch_label);
241990075Sobrien      sjlj_emit_dispatch_table (dispatch_label, lp_info);
242090075Sobrien      sjlj_emit_function_exit ();
242150397Sobrien    }
242250397Sobrien
242390075Sobrien  free (lp_info);
242450397Sobrien}
242550397Sobrien
242652284Sobrienvoid
242790075Sobrienfinish_eh_generation ()
242850397Sobrien{
242990075Sobrien  /* Nothing to do if no regions created.  */
243090075Sobrien  if (cfun->eh->region_tree == NULL)
243190075Sobrien    return;
243250397Sobrien
243390075Sobrien  /* The object here is to provide find_basic_blocks with detailed
243490075Sobrien     information (via reachable_handlers) on how exception control
243590075Sobrien     flows within the function.  In this first pass, we can include
243690075Sobrien     type information garnered from ERT_THROW and ERT_ALLOWED_EXCEPTIONS
243790075Sobrien     regions, and hope that it will be useful in deleting unreachable
243890075Sobrien     handlers.  Subsequently, we will generate landing pads which will
243990075Sobrien     connect many of the handlers, and then type information will not
244090075Sobrien     be effective.  Still, this is a win over previous implementations.  */
244150397Sobrien
244290075Sobrien  rebuild_jump_labels (get_insns ());
244390075Sobrien  find_basic_blocks (get_insns (), max_reg_num (), 0);
244490075Sobrien  cleanup_cfg (CLEANUP_PRE_LOOP);
244550397Sobrien
244690075Sobrien  /* These registers are used by the landing pads.  Make sure they
244790075Sobrien     have been generated.  */
244890075Sobrien  get_exception_pointer (cfun);
244990075Sobrien  get_exception_filter (cfun);
245050397Sobrien
245190075Sobrien  /* Construct the landing pads.  */
245250397Sobrien
245390075Sobrien  assign_filter_values ();
245490075Sobrien  build_post_landing_pads ();
245590075Sobrien  connect_post_landing_pads ();
245690075Sobrien  if (USING_SJLJ_EXCEPTIONS)
245790075Sobrien    sjlj_build_landing_pads ();
245890075Sobrien  else
245990075Sobrien    dw2_build_landing_pads ();
246050397Sobrien
246190075Sobrien  cfun->eh->built_landing_pads = 1;
246250397Sobrien
246390075Sobrien  /* We've totally changed the CFG.  Start over.  */
246490075Sobrien  find_exception_handler_labels ();
246590075Sobrien  rebuild_jump_labels (get_insns ());
246690075Sobrien  find_basic_blocks (get_insns (), max_reg_num (), 0);
246790075Sobrien  cleanup_cfg (CLEANUP_PRE_LOOP);
246890075Sobrien}
246990075Sobrien
247090075Sobrien/* This section handles removing dead code for flow.  */
247152284Sobrien
247290075Sobrien/* Remove LABEL from the exception_handler_labels list.  */
247350397Sobrien
247490075Sobrienstatic void
247590075Sobrienremove_exception_handler_label (label)
247690075Sobrien     rtx label;
247790075Sobrien{
247890075Sobrien  rtx *pl, l;
247950397Sobrien
248090075Sobrien  /* If exception_handler_labels was not built yet,
248190075Sobrien     there is nothing to do.  */
248290075Sobrien  if (exception_handler_labels == NULL)
248390075Sobrien    return;
248450397Sobrien
248590075Sobrien  for (pl = &exception_handler_labels, l = *pl;
248690075Sobrien       XEXP (l, 0) != label;
248790075Sobrien       pl = &XEXP (l, 1), l = *pl)
248890075Sobrien    continue;
248950397Sobrien
249090075Sobrien  *pl = XEXP (l, 1);
249190075Sobrien  free_EXPR_LIST_node (l);
249250397Sobrien}
249350397Sobrien
249490075Sobrien/* Splice REGION from the region tree etc.  */
249550397Sobrien
249690075Sobrienstatic void
249790075Sobrienremove_eh_handler (region)
249890075Sobrien     struct eh_region *region;
249950397Sobrien{
250090075Sobrien  struct eh_region **pp, *p;
250190075Sobrien  rtx lab;
250290075Sobrien  int i;
250350397Sobrien
250490075Sobrien  /* For the benefit of efficiently handling REG_EH_REGION notes,
250590075Sobrien     replace this region in the region array with its containing
250690075Sobrien     region.  Note that previous region deletions may result in
250790075Sobrien     multiple copies of this region in the array, so we have to
250890075Sobrien     search the whole thing.  */
250990075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
251090075Sobrien    if (cfun->eh->region_array[i] == region)
251190075Sobrien      cfun->eh->region_array[i] = region->outer;
251250397Sobrien
251390075Sobrien  if (cfun->eh->built_landing_pads)
251490075Sobrien    lab = region->landing_pad;
251590075Sobrien  else
251690075Sobrien    lab = region->label;
251790075Sobrien  if (lab)
251890075Sobrien    remove_exception_handler_label (lab);
251950397Sobrien
252090075Sobrien  if (region->outer)
252190075Sobrien    pp = &region->outer->inner;
252290075Sobrien  else
252390075Sobrien    pp = &cfun->eh->region_tree;
252490075Sobrien  for (p = *pp; p != region; pp = &p->next_peer, p = *pp)
252590075Sobrien    continue;
252650397Sobrien
252790075Sobrien  if (region->inner)
252890075Sobrien    {
252990075Sobrien      for (p = region->inner; p->next_peer ; p = p->next_peer)
253090075Sobrien	p->outer = region->outer;
253190075Sobrien      p->next_peer = region->next_peer;
253290075Sobrien      p->outer = region->outer;
253390075Sobrien      *pp = region->inner;
253490075Sobrien    }
253590075Sobrien  else
253690075Sobrien    *pp = region->next_peer;
253750397Sobrien
253890075Sobrien  if (region->type == ERT_CATCH)
253990075Sobrien    {
254090075Sobrien      struct eh_region *try, *next, *prev;
254152284Sobrien
254290075Sobrien      for (try = region->next_peer;
254390075Sobrien	   try->type == ERT_CATCH;
254490075Sobrien	   try = try->next_peer)
254590075Sobrien	continue;
254690075Sobrien      if (try->type != ERT_TRY)
254790075Sobrien	abort ();
254890075Sobrien
254990075Sobrien      next = region->u.catch.next_catch;
255090075Sobrien      prev = region->u.catch.prev_catch;
255190075Sobrien
255290075Sobrien      if (next)
255390075Sobrien	next->u.catch.prev_catch = prev;
255490075Sobrien      else
255590075Sobrien	try->u.try.last_catch = prev;
255690075Sobrien      if (prev)
255790075Sobrien	prev->u.catch.next_catch = next;
255890075Sobrien      else
255990075Sobrien	{
256090075Sobrien	  try->u.try.catch = next;
256190075Sobrien	  if (! next)
256290075Sobrien	    remove_eh_handler (try);
256390075Sobrien	}
256490075Sobrien    }
256590075Sobrien
256690075Sobrien  free (region);
256750397Sobrien}
256850397Sobrien
256990075Sobrien/* LABEL heads a basic block that is about to be deleted.  If this
257090075Sobrien   label corresponds to an exception region, we may be able to
257190075Sobrien   delete the region.  */
257250397Sobrien
257350397Sobrienvoid
257490075Sobrienmaybe_remove_eh_handler (label)
257590075Sobrien     rtx label;
257650397Sobrien{
257790075Sobrien  int i;
257850397Sobrien
257990075Sobrien  /* ??? After generating landing pads, it's not so simple to determine
258090075Sobrien     if the region data is completely unused.  One must examine the
258190075Sobrien     landing pad and the post landing pad, and whether an inner try block
258290075Sobrien     is referencing the catch handlers directly.  */
258390075Sobrien  if (cfun->eh->built_landing_pads)
258450397Sobrien    return;
258550397Sobrien
258690075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
258750397Sobrien    {
258890075Sobrien      struct eh_region *region = cfun->eh->region_array[i];
258990075Sobrien      if (region && region->label == label)
259050397Sobrien	{
259190075Sobrien	  /* Flow will want to remove MUST_NOT_THROW regions as unreachable
259290075Sobrien	     because there is no path to the fallback call to terminate.
259390075Sobrien	     But the region continues to affect call-site data until there
259490075Sobrien	     are no more contained calls, which we don't see here.  */
259590075Sobrien	  if (region->type == ERT_MUST_NOT_THROW)
259690075Sobrien	    {
259790075Sobrien	      remove_exception_handler_label (region->label);
259890075Sobrien	      region->label = NULL_RTX;
259990075Sobrien	    }
260090075Sobrien	  else
260190075Sobrien	    remove_eh_handler (region);
260290075Sobrien	  break;
260350397Sobrien	}
260450397Sobrien    }
260550397Sobrien}
260650397Sobrien
260790075Sobrien
260890075Sobrien/* This section describes CFG exception edges for flow.  */
260950397Sobrien
261090075Sobrien/* For communicating between calls to reachable_next_level.  */
261190075Sobrienstruct reachable_info
261250397Sobrien{
261390075Sobrien  tree types_caught;
261490075Sobrien  tree types_allowed;
261590075Sobrien  rtx handlers;
261690075Sobrien};
261790075Sobrien
261890075Sobrien/* A subroutine of reachable_next_level.  Return true if TYPE, or a
261990075Sobrien   base class of TYPE, is in HANDLED.  */
262090075Sobrien
262190075Sobrienstatic int
262290075Sobriencheck_handled (handled, type)
262390075Sobrien     tree handled, type;
262490075Sobrien{
262590075Sobrien  tree t;
262690075Sobrien
262790075Sobrien  /* We can check for exact matches without front-end help.  */
262890075Sobrien  if (! lang_eh_type_covers)
262990075Sobrien    {
263090075Sobrien      for (t = handled; t ; t = TREE_CHAIN (t))
263190075Sobrien	if (TREE_VALUE (t) == type)
263290075Sobrien	  return 1;
263390075Sobrien    }
263490075Sobrien  else
263590075Sobrien    {
263690075Sobrien      for (t = handled; t ; t = TREE_CHAIN (t))
263790075Sobrien	if ((*lang_eh_type_covers) (TREE_VALUE (t), type))
263890075Sobrien	  return 1;
263990075Sobrien    }
264090075Sobrien
264150397Sobrien  return 0;
264250397Sobrien}
264350397Sobrien
264490075Sobrien/* A subroutine of reachable_next_level.  If we are collecting a list
264590075Sobrien   of handlers, add one.  After landing pad generation, reference
264690075Sobrien   it instead of the handlers themselves.  Further, the handlers are
264790075Sobrien   all wired together, so by referencing one, we've got them all.
264890075Sobrien   Before landing pad generation we reference each handler individually.
264950397Sobrien
265090075Sobrien   LP_REGION contains the landing pad; REGION is the handler.  */
265150397Sobrien
265290075Sobrienstatic void
265390075Sobrienadd_reachable_handler (info, lp_region, region)
265490075Sobrien     struct reachable_info *info;
265590075Sobrien     struct eh_region *lp_region;
265690075Sobrien     struct eh_region *region;
265750397Sobrien{
265890075Sobrien  if (! info)
265950397Sobrien    return;
266050397Sobrien
266190075Sobrien  if (cfun->eh->built_landing_pads)
266250397Sobrien    {
266390075Sobrien      if (! info->handlers)
266490075Sobrien	info->handlers = alloc_INSN_LIST (lp_region->landing_pad, NULL_RTX);
266550397Sobrien    }
266690075Sobrien  else
266790075Sobrien    info->handlers = alloc_INSN_LIST (region->label, info->handlers);
266850397Sobrien}
266950397Sobrien
267090075Sobrien/* Process one level of exception regions for reachability.
267190075Sobrien   If TYPE_THROWN is non-null, then it is the *exact* type being
267290075Sobrien   propagated.  If INFO is non-null, then collect handler labels
267390075Sobrien   and caught/allowed type information between invocations.  */
267450397Sobrien
267590075Sobrienstatic enum reachable_code
267690075Sobrienreachable_next_level (region, type_thrown, info)
267790075Sobrien     struct eh_region *region;
267890075Sobrien     tree type_thrown;
267990075Sobrien     struct reachable_info *info;
268050397Sobrien{
268190075Sobrien  switch (region->type)
268290075Sobrien    {
268390075Sobrien    case ERT_CLEANUP:
268490075Sobrien      /* Before landing-pad generation, we model control flow
268590075Sobrien	 directly to the individual handlers.  In this way we can
268690075Sobrien	 see that catch handler types may shadow one another.  */
268790075Sobrien      add_reachable_handler (info, region, region);
268890075Sobrien      return RNL_MAYBE_CAUGHT;
268950397Sobrien
269090075Sobrien    case ERT_TRY:
269190075Sobrien      {
269290075Sobrien	struct eh_region *c;
269390075Sobrien	enum reachable_code ret = RNL_NOT_CAUGHT;
269450397Sobrien
269590075Sobrien	for (c = region->u.try.catch; c ; c = c->u.catch.next_catch)
269690075Sobrien	  {
269790075Sobrien	    /* A catch-all handler ends the search.  */
269890075Sobrien	    /* ??? _Unwind_ForcedUnwind will want outer cleanups
269990075Sobrien	       to be run as well.  */
270090075Sobrien	    if (c->u.catch.type_list == NULL)
270190075Sobrien	      {
270290075Sobrien		add_reachable_handler (info, region, c);
270390075Sobrien		return RNL_CAUGHT;
270490075Sobrien	      }
270550397Sobrien
270690075Sobrien	    if (type_thrown)
270790075Sobrien	      {
270890075Sobrien		/* If we have at least one type match, end the search.  */
270990075Sobrien		tree tp_node = c->u.catch.type_list;
271050397Sobrien
271190075Sobrien		for (; tp_node; tp_node = TREE_CHAIN (tp_node))
271290075Sobrien		  {
271390075Sobrien		    tree type = TREE_VALUE (tp_node);
271450397Sobrien
271590075Sobrien		    if (type == type_thrown
271690075Sobrien			|| (lang_eh_type_covers
271790075Sobrien			    && (*lang_eh_type_covers) (type, type_thrown)))
271890075Sobrien		      {
271990075Sobrien			add_reachable_handler (info, region, c);
272090075Sobrien			return RNL_CAUGHT;
272190075Sobrien		      }
272290075Sobrien		  }
272350397Sobrien
272490075Sobrien		/* If we have definitive information of a match failure,
272590075Sobrien		   the catch won't trigger.  */
272690075Sobrien		if (lang_eh_type_covers)
272790075Sobrien		  return RNL_NOT_CAUGHT;
272890075Sobrien	      }
272950397Sobrien
273090075Sobrien	    /* At this point, we either don't know what type is thrown or
273190075Sobrien	       don't have front-end assistance to help deciding if it is
273290075Sobrien	       covered by one of the types in the list for this region.
273350397Sobrien
273490075Sobrien	       We'd then like to add this region to the list of reachable
273590075Sobrien	       handlers since it is indeed potentially reachable based on the
273690075Sobrien	       information we have.
273750397Sobrien
273890075Sobrien	       Actually, this handler is for sure not reachable if all the
273990075Sobrien	       types it matches have already been caught. That is, it is only
274090075Sobrien	       potentially reachable if at least one of the types it catches
274190075Sobrien	       has not been previously caught.  */
274250397Sobrien
274390075Sobrien	    if (! info)
274490075Sobrien	      ret = RNL_MAYBE_CAUGHT;
274590075Sobrien	    else
274690075Sobrien	      {
274790075Sobrien		tree tp_node = c->u.catch.type_list;
274890075Sobrien		bool maybe_reachable = false;
274950397Sobrien
275090075Sobrien		/* Compute the potential reachability of this handler and
275190075Sobrien		   update the list of types caught at the same time.  */
275290075Sobrien		for (; tp_node; tp_node = TREE_CHAIN (tp_node))
275390075Sobrien		  {
275490075Sobrien		    tree type = TREE_VALUE (tp_node);
275590075Sobrien
275690075Sobrien		    if (! check_handled (info->types_caught, type))
275790075Sobrien		      {
275890075Sobrien			info->types_caught
275990075Sobrien			  = tree_cons (NULL, type, info->types_caught);
276090075Sobrien
276190075Sobrien			maybe_reachable = true;
276290075Sobrien		      }
276390075Sobrien		  }
276490075Sobrien
276590075Sobrien		if (maybe_reachable)
276690075Sobrien		  {
276790075Sobrien		    add_reachable_handler (info, region, c);
276890075Sobrien
276990075Sobrien		    /* ??? If the catch type is a base class of every allowed
277090075Sobrien		       type, then we know we can stop the search.  */
277190075Sobrien		    ret = RNL_MAYBE_CAUGHT;
277290075Sobrien		  }
277390075Sobrien	      }
277490075Sobrien	  }
277590075Sobrien
277690075Sobrien	return ret;
277790075Sobrien      }
277890075Sobrien
277990075Sobrien    case ERT_ALLOWED_EXCEPTIONS:
278090075Sobrien      /* An empty list of types definitely ends the search.  */
278190075Sobrien      if (region->u.allowed.type_list == NULL_TREE)
278290075Sobrien	{
278390075Sobrien	  add_reachable_handler (info, region, region);
278490075Sobrien	  return RNL_CAUGHT;
278590075Sobrien	}
278690075Sobrien
278790075Sobrien      /* Collect a list of lists of allowed types for use in detecting
278890075Sobrien	 when a catch may be transformed into a catch-all.  */
278990075Sobrien      if (info)
279090075Sobrien	info->types_allowed = tree_cons (NULL_TREE,
279190075Sobrien					 region->u.allowed.type_list,
279290075Sobrien					 info->types_allowed);
279390075Sobrien
279490075Sobrien      /* If we have definitive information about the type hierarchy,
279590075Sobrien	 then we can tell if the thrown type will pass through the
279690075Sobrien	 filter.  */
279790075Sobrien      if (type_thrown && lang_eh_type_covers)
279890075Sobrien	{
279990075Sobrien	  if (check_handled (region->u.allowed.type_list, type_thrown))
280090075Sobrien	    return RNL_NOT_CAUGHT;
280190075Sobrien	  else
280290075Sobrien	    {
280390075Sobrien	      add_reachable_handler (info, region, region);
280490075Sobrien	      return RNL_CAUGHT;
280590075Sobrien	    }
280690075Sobrien	}
280790075Sobrien
280890075Sobrien      add_reachable_handler (info, region, region);
280990075Sobrien      return RNL_MAYBE_CAUGHT;
281090075Sobrien
281190075Sobrien    case ERT_CATCH:
281290075Sobrien      /* Catch regions are handled by their controling try region.  */
281390075Sobrien      return RNL_NOT_CAUGHT;
281490075Sobrien
281590075Sobrien    case ERT_MUST_NOT_THROW:
281690075Sobrien      /* Here we end our search, since no exceptions may propagate.
281790075Sobrien	 If we've touched down at some landing pad previous, then the
281890075Sobrien	 explicit function call we generated may be used.  Otherwise
281990075Sobrien	 the call is made by the runtime.  */
282090075Sobrien      if (info && info->handlers)
282190075Sobrien	{
282290075Sobrien	  add_reachable_handler (info, region, region);
282390075Sobrien          return RNL_CAUGHT;
282490075Sobrien	}
282590075Sobrien      else
282690075Sobrien	return RNL_BLOCKED;
282790075Sobrien
282890075Sobrien    case ERT_THROW:
282990075Sobrien    case ERT_FIXUP:
283090075Sobrien    case ERT_UNKNOWN:
283190075Sobrien      /* Shouldn't see these here.  */
283290075Sobrien      break;
283390075Sobrien    }
283490075Sobrien
283590075Sobrien  abort ();
283650397Sobrien}
283750397Sobrien
283890075Sobrien/* Retrieve a list of labels of exception handlers which can be
283990075Sobrien   reached by a given insn.  */
284050397Sobrien
284190075Sobrienrtx
284290075Sobrienreachable_handlers (insn)
284350397Sobrien     rtx insn;
284450397Sobrien{
284590075Sobrien  struct reachable_info info;
284690075Sobrien  struct eh_region *region;
284790075Sobrien  tree type_thrown;
284890075Sobrien  int region_number;
284950397Sobrien
285090075Sobrien  if (GET_CODE (insn) == JUMP_INSN
285190075Sobrien      && GET_CODE (PATTERN (insn)) == RESX)
285290075Sobrien    region_number = XINT (PATTERN (insn), 0);
285390075Sobrien  else
285450397Sobrien    {
285590075Sobrien      rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
285690075Sobrien      if (!note || INTVAL (XEXP (note, 0)) <= 0)
285790075Sobrien	return NULL;
285890075Sobrien      region_number = INTVAL (XEXP (note, 0));
285950397Sobrien    }
286050397Sobrien
286190075Sobrien  memset (&info, 0, sizeof (info));
286250397Sobrien
286390075Sobrien  region = cfun->eh->region_array[region_number];
286450397Sobrien
286590075Sobrien  type_thrown = NULL_TREE;
286690075Sobrien  if (GET_CODE (insn) == JUMP_INSN
286790075Sobrien      && GET_CODE (PATTERN (insn)) == RESX)
286890075Sobrien    {
286990075Sobrien      /* A RESX leaves a region instead of entering it.  Thus the
287090075Sobrien	 region itself may have been deleted out from under us.  */
287190075Sobrien      if (region == NULL)
287290075Sobrien	return NULL;
287390075Sobrien      region = region->outer;
287490075Sobrien    }
287590075Sobrien  else if (region->type == ERT_THROW)
287690075Sobrien    {
287790075Sobrien      type_thrown = region->u.throw.type;
287890075Sobrien      region = region->outer;
287990075Sobrien    }
288050397Sobrien
288190075Sobrien  for (; region; region = region->outer)
288290075Sobrien    if (reachable_next_level (region, type_thrown, &info) >= RNL_CAUGHT)
288390075Sobrien      break;
288450397Sobrien
288590075Sobrien  return info.handlers;
288690075Sobrien}
288750397Sobrien
288890075Sobrien/* Determine if the given INSN can throw an exception that is caught
288990075Sobrien   within the function.  */
289090075Sobrien
289190075Sobrienbool
289290075Sobriencan_throw_internal (insn)
289350397Sobrien     rtx insn;
289450397Sobrien{
289590075Sobrien  struct eh_region *region;
289690075Sobrien  tree type_thrown;
289790075Sobrien  rtx note;
289850397Sobrien
289990075Sobrien  if (! INSN_P (insn))
290090075Sobrien    return false;
290150397Sobrien
290290075Sobrien  if (GET_CODE (insn) == INSN
290390075Sobrien      && GET_CODE (PATTERN (insn)) == SEQUENCE)
290490075Sobrien    insn = XVECEXP (PATTERN (insn), 0, 0);
290552284Sobrien
290690075Sobrien  if (GET_CODE (insn) == CALL_INSN
290790075Sobrien      && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
290850397Sobrien    {
290990075Sobrien      int i;
291090075Sobrien      for (i = 0; i < 3; ++i)
291150397Sobrien	{
291290075Sobrien	  rtx sub = XEXP (PATTERN (insn), i);
291390075Sobrien	  for (; sub ; sub = NEXT_INSN (sub))
291490075Sobrien	    if (can_throw_internal (sub))
291590075Sobrien	      return true;
291650397Sobrien	}
291790075Sobrien      return false;
291890075Sobrien    }
291950397Sobrien
292090075Sobrien  /* Every insn that might throw has an EH_REGION note.  */
292190075Sobrien  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
292290075Sobrien  if (!note || INTVAL (XEXP (note, 0)) <= 0)
292390075Sobrien    return false;
292450397Sobrien
292590075Sobrien  region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
292690075Sobrien
292790075Sobrien  type_thrown = NULL_TREE;
292890075Sobrien  if (region->type == ERT_THROW)
292990075Sobrien    {
293090075Sobrien      type_thrown = region->u.throw.type;
293190075Sobrien      region = region->outer;
293250397Sobrien    }
293350397Sobrien
293490075Sobrien  /* If this exception is ignored by each and every containing region,
293590075Sobrien     then control passes straight out.  The runtime may handle some
293690075Sobrien     regions, which also do not require processing internally.  */
293790075Sobrien  for (; region; region = region->outer)
293850397Sobrien    {
293990075Sobrien      enum reachable_code how = reachable_next_level (region, type_thrown, 0);
294090075Sobrien      if (how == RNL_BLOCKED)
294190075Sobrien	return false;
294290075Sobrien      if (how != RNL_NOT_CAUGHT)
294390075Sobrien        return true;
294490075Sobrien    }
294550397Sobrien
294690075Sobrien  return false;
294790075Sobrien}
294850397Sobrien
294990075Sobrien/* Determine if the given INSN can throw an exception that is
295090075Sobrien   visible outside the function.  */
295150397Sobrien
295290075Sobrienbool
295390075Sobriencan_throw_external (insn)
295490075Sobrien     rtx insn;
295590075Sobrien{
295690075Sobrien  struct eh_region *region;
295790075Sobrien  tree type_thrown;
295890075Sobrien  rtx note;
295950397Sobrien
296090075Sobrien  if (! INSN_P (insn))
296190075Sobrien    return false;
296290075Sobrien
296390075Sobrien  if (GET_CODE (insn) == INSN
296490075Sobrien      && GET_CODE (PATTERN (insn)) == SEQUENCE)
296590075Sobrien    insn = XVECEXP (PATTERN (insn), 0, 0);
296690075Sobrien
296790075Sobrien  if (GET_CODE (insn) == CALL_INSN
296890075Sobrien      && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
296990075Sobrien    {
297090075Sobrien      int i;
297190075Sobrien      for (i = 0; i < 3; ++i)
297290075Sobrien	{
297390075Sobrien	  rtx sub = XEXP (PATTERN (insn), i);
297490075Sobrien	  for (; sub ; sub = NEXT_INSN (sub))
297590075Sobrien	    if (can_throw_external (sub))
297690075Sobrien	      return true;
297750397Sobrien	}
297890075Sobrien      return false;
297950397Sobrien    }
298090075Sobrien
298190075Sobrien  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
298290075Sobrien  if (!note)
298390075Sobrien    {
298490075Sobrien      /* Calls (and trapping insns) without notes are outside any
298590075Sobrien	 exception handling region in this function.  We have to
298690075Sobrien	 assume it might throw.  Given that the front end and middle
298790075Sobrien	 ends mark known NOTHROW functions, this isn't so wildly
298890075Sobrien	 inaccurate.  */
298990075Sobrien      return (GET_CODE (insn) == CALL_INSN
299090075Sobrien	      || (flag_non_call_exceptions
299190075Sobrien		  && may_trap_p (PATTERN (insn))));
299290075Sobrien    }
299390075Sobrien  if (INTVAL (XEXP (note, 0)) <= 0)
299490075Sobrien    return false;
299590075Sobrien
299690075Sobrien  region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
299790075Sobrien
299890075Sobrien  type_thrown = NULL_TREE;
299990075Sobrien  if (region->type == ERT_THROW)
300090075Sobrien    {
300190075Sobrien      type_thrown = region->u.throw.type;
300290075Sobrien      region = region->outer;
300390075Sobrien    }
300490075Sobrien
300590075Sobrien  /* If the exception is caught or blocked by any containing region,
300690075Sobrien     then it is not seen by any calling function.  */
300790075Sobrien  for (; region ; region = region->outer)
300890075Sobrien    if (reachable_next_level (region, type_thrown, NULL) >= RNL_CAUGHT)
300990075Sobrien      return false;
301090075Sobrien
301190075Sobrien  return true;
301250397Sobrien}
301350397Sobrien
301490075Sobrien/* True if nothing in this function can throw outside this function.  */
301550397Sobrien
301690075Sobrienbool
301790075Sobriennothrow_function_p ()
301850397Sobrien{
301950397Sobrien  rtx insn;
302050397Sobrien
302190075Sobrien  if (! flag_exceptions)
302290075Sobrien    return true;
302390075Sobrien
302450397Sobrien  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
302590075Sobrien    if (can_throw_external (insn))
302690075Sobrien      return false;
302790075Sobrien  for (insn = current_function_epilogue_delay_list; insn;
302890075Sobrien       insn = XEXP (insn, 1))
302990075Sobrien    if (can_throw_external (insn))
303090075Sobrien      return false;
303190075Sobrien
303290075Sobrien  return true;
303350397Sobrien}
303490075Sobrien
303550397Sobrien
303690075Sobrien/* Various hooks for unwind library.  */
303750397Sobrien
303850397Sobrien/* Do any necessary initialization to access arbitrary stack frames.
303950397Sobrien   On the SPARC, this means flushing the register windows.  */
304050397Sobrien
304150397Sobrienvoid
304250397Sobrienexpand_builtin_unwind_init ()
304350397Sobrien{
304450397Sobrien  /* Set this so all the registers get saved in our frame; we need to be
304590075Sobrien     able to copy the saved values for any registers from frames we unwind.  */
304650397Sobrien  current_function_has_nonlocal_label = 1;
304750397Sobrien
304850397Sobrien#ifdef SETUP_FRAME_ADDRESSES
304950397Sobrien  SETUP_FRAME_ADDRESSES ();
305050397Sobrien#endif
305150397Sobrien}
305250397Sobrien
305390075Sobrienrtx
305490075Sobrienexpand_builtin_eh_return_data_regno (arglist)
305590075Sobrien     tree arglist;
305690075Sobrien{
305790075Sobrien  tree which = TREE_VALUE (arglist);
305890075Sobrien  unsigned HOST_WIDE_INT iwhich;
305990075Sobrien
306090075Sobrien  if (TREE_CODE (which) != INTEGER_CST)
306190075Sobrien    {
306290075Sobrien      error ("argument of `__builtin_eh_return_regno' must be constant");
306390075Sobrien      return constm1_rtx;
306490075Sobrien    }
306590075Sobrien
306690075Sobrien  iwhich = tree_low_cst (which, 1);
306790075Sobrien  iwhich = EH_RETURN_DATA_REGNO (iwhich);
306890075Sobrien  if (iwhich == INVALID_REGNUM)
306990075Sobrien    return constm1_rtx;
307090075Sobrien
307190075Sobrien#ifdef DWARF_FRAME_REGNUM
307290075Sobrien  iwhich = DWARF_FRAME_REGNUM (iwhich);
307390075Sobrien#else
307490075Sobrien  iwhich = DBX_REGISTER_NUMBER (iwhich);
307590075Sobrien#endif
307690075Sobrien
307790075Sobrien  return GEN_INT (iwhich);
307890075Sobrien}
307990075Sobrien
308050397Sobrien/* Given a value extracted from the return address register or stack slot,
308150397Sobrien   return the actual address encoded in that value.  */
308250397Sobrien
308350397Sobrienrtx
308450397Sobrienexpand_builtin_extract_return_addr (addr_tree)
308550397Sobrien     tree addr_tree;
308650397Sobrien{
308750397Sobrien  rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
308890075Sobrien
308990075Sobrien  /* First mask out any unwanted bits.  */
309090075Sobrien#ifdef MASK_RETURN_ADDR
309190075Sobrien  expand_and (addr, MASK_RETURN_ADDR, addr);
309290075Sobrien#endif
309390075Sobrien
309490075Sobrien  /* Then adjust to find the real return address.  */
309590075Sobrien#if defined (RETURN_ADDR_OFFSET)
309690075Sobrien  addr = plus_constant (addr, RETURN_ADDR_OFFSET);
309790075Sobrien#endif
309890075Sobrien
309990075Sobrien  return addr;
310050397Sobrien}
310150397Sobrien
310250397Sobrien/* Given an actual address in addr_tree, do any necessary encoding
310350397Sobrien   and return the value to be stored in the return address register or
310450397Sobrien   stack slot so the epilogue will return to that address.  */
310550397Sobrien
310650397Sobrienrtx
310750397Sobrienexpand_builtin_frob_return_addr (addr_tree)
310850397Sobrien     tree addr_tree;
310950397Sobrien{
311090075Sobrien  rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, 0);
311190075Sobrien
311290075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED
311390075Sobrien  if (GET_MODE (addr) != Pmode)
311490075Sobrien    addr = convert_memory_address (Pmode, addr);
311590075Sobrien#endif
311690075Sobrien
311750397Sobrien#ifdef RETURN_ADDR_OFFSET
311890075Sobrien  addr = force_reg (Pmode, addr);
311950397Sobrien  addr = plus_constant (addr, -RETURN_ADDR_OFFSET);
312050397Sobrien#endif
312190075Sobrien
312250397Sobrien  return addr;
312350397Sobrien}
312450397Sobrien
312590075Sobrien/* Set up the epilogue with the magic bits we'll need to return to the
312690075Sobrien   exception handler.  */
312750397Sobrien
312890075Sobrienvoid
312990075Sobrienexpand_builtin_eh_return (stackadj_tree, handler_tree)
313090075Sobrien    tree stackadj_tree, handler_tree;
313190075Sobrien{
313290075Sobrien  rtx stackadj, handler;
313350397Sobrien
313490075Sobrien  stackadj = expand_expr (stackadj_tree, cfun->eh->ehr_stackadj, VOIDmode, 0);
313590075Sobrien  handler = expand_expr (handler_tree, cfun->eh->ehr_handler, VOIDmode, 0);
313650397Sobrien
313790075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED
313890075Sobrien  if (GET_MODE (stackadj) != Pmode)
313990075Sobrien    stackadj = convert_memory_address (Pmode, stackadj);
314050397Sobrien
314190075Sobrien  if (GET_MODE (handler) != Pmode)
314290075Sobrien    handler = convert_memory_address (Pmode, handler);
314350397Sobrien#endif
314450397Sobrien
314590075Sobrien  if (! cfun->eh->ehr_label)
314690075Sobrien    {
314790075Sobrien      cfun->eh->ehr_stackadj = copy_to_reg (stackadj);
314890075Sobrien      cfun->eh->ehr_handler = copy_to_reg (handler);
314990075Sobrien      cfun->eh->ehr_label = gen_label_rtx ();
315090075Sobrien    }
315150397Sobrien  else
315290075Sobrien    {
315390075Sobrien      if (stackadj != cfun->eh->ehr_stackadj)
315490075Sobrien	emit_move_insn (cfun->eh->ehr_stackadj, stackadj);
315590075Sobrien      if (handler != cfun->eh->ehr_handler)
315690075Sobrien	emit_move_insn (cfun->eh->ehr_handler, handler);
315790075Sobrien    }
315850397Sobrien
315990075Sobrien  emit_jump (cfun->eh->ehr_label);
316090075Sobrien}
316190075Sobrien
316290075Sobrienvoid
316390075Sobrienexpand_eh_return ()
316490075Sobrien{
316590075Sobrien  rtx sa, ra, around_label;
316690075Sobrien
316790075Sobrien  if (! cfun->eh->ehr_label)
316890075Sobrien    return;
316990075Sobrien
317090075Sobrien  sa = EH_RETURN_STACKADJ_RTX;
317190075Sobrien  if (! sa)
317250397Sobrien    {
317390075Sobrien      error ("__builtin_eh_return not supported on this target");
317490075Sobrien      return;
317590075Sobrien    }
317650397Sobrien
317790075Sobrien  current_function_calls_eh_return = 1;
317890075Sobrien
317990075Sobrien  around_label = gen_label_rtx ();
318090075Sobrien  emit_move_insn (sa, const0_rtx);
318190075Sobrien  emit_jump (around_label);
318290075Sobrien
318390075Sobrien  emit_label (cfun->eh->ehr_label);
318490075Sobrien  clobber_return_register ();
318590075Sobrien
318690075Sobrien#ifdef HAVE_eh_return
318790075Sobrien  if (HAVE_eh_return)
318890075Sobrien    emit_insn (gen_eh_return (cfun->eh->ehr_stackadj, cfun->eh->ehr_handler));
318990075Sobrien  else
319090075Sobrien#endif
319190075Sobrien    {
319290075Sobrien      ra = EH_RETURN_HANDLER_RTX;
319390075Sobrien      if (! ra)
319490075Sobrien	{
319590075Sobrien	  error ("__builtin_eh_return not supported on this target");
319690075Sobrien	  ra = gen_reg_rtx (Pmode);
319790075Sobrien	}
319890075Sobrien
319990075Sobrien      emit_move_insn (sa, cfun->eh->ehr_stackadj);
320090075Sobrien      emit_move_insn (ra, cfun->eh->ehr_handler);
320150397Sobrien    }
320250397Sobrien
320390075Sobrien  emit_label (around_label);
320490075Sobrien}
320590075Sobrien
320690075Sobrien/* In the following functions, we represent entries in the action table
320790075Sobrien   as 1-based indices.  Special cases are:
320852284Sobrien
320990075Sobrien	 0:	null action record, non-null landing pad; implies cleanups
321090075Sobrien	-1:	null action record, null landing pad; implies no action
321190075Sobrien	-2:	no call-site entry; implies must_not_throw
321290075Sobrien	-3:	we have yet to process outer regions
321352284Sobrien
321490075Sobrien   Further, no special cases apply to the "next" field of the record.
321590075Sobrien   For next, 0 means end of list.  */
321690075Sobrien
321790075Sobrienstruct action_record
321890075Sobrien{
321990075Sobrien  int offset;
322090075Sobrien  int filter;
322190075Sobrien  int next;
322290075Sobrien};
322390075Sobrien
322490075Sobrienstatic int
322590075Sobrienaction_record_eq (pentry, pdata)
322690075Sobrien     const PTR pentry;
322790075Sobrien     const PTR pdata;
322890075Sobrien{
322990075Sobrien  const struct action_record *entry = (const struct action_record *) pentry;
323090075Sobrien  const struct action_record *data = (const struct action_record *) pdata;
323190075Sobrien  return entry->filter == data->filter && entry->next == data->next;
323250397Sobrien}
323350397Sobrien
323490075Sobrienstatic hashval_t
323590075Sobrienaction_record_hash (pentry)
323690075Sobrien     const PTR pentry;
323790075Sobrien{
323890075Sobrien  const struct action_record *entry = (const struct action_record *) pentry;
323990075Sobrien  return entry->next * 1009 + entry->filter;
324090075Sobrien}
324150397Sobrien
324290075Sobrienstatic int
324390075Sobrienadd_action_record (ar_hash, filter, next)
324490075Sobrien     htab_t ar_hash;
324590075Sobrien     int filter, next;
324650397Sobrien{
324790075Sobrien  struct action_record **slot, *new, tmp;
324890075Sobrien
324990075Sobrien  tmp.filter = filter;
325090075Sobrien  tmp.next = next;
325190075Sobrien  slot = (struct action_record **) htab_find_slot (ar_hash, &tmp, INSERT);
325290075Sobrien
325390075Sobrien  if ((new = *slot) == NULL)
325490075Sobrien    {
325590075Sobrien      new = (struct action_record *) xmalloc (sizeof (*new));
325690075Sobrien      new->offset = VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) + 1;
325790075Sobrien      new->filter = filter;
325890075Sobrien      new->next = next;
325990075Sobrien      *slot = new;
326090075Sobrien
326190075Sobrien      /* The filter value goes in untouched.  The link to the next
326290075Sobrien	 record is a "self-relative" byte offset, or zero to indicate
326390075Sobrien	 that there is no next record.  So convert the absolute 1 based
326490075Sobrien	 indices we've been carrying around into a displacement.  */
326590075Sobrien
326690075Sobrien      push_sleb128 (&cfun->eh->action_record_data, filter);
326790075Sobrien      if (next)
326890075Sobrien	next -= VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) + 1;
326990075Sobrien      push_sleb128 (&cfun->eh->action_record_data, next);
327090075Sobrien    }
327190075Sobrien
327290075Sobrien  return new->offset;
327350397Sobrien}
327450397Sobrien
327590075Sobrienstatic int
327690075Sobriencollect_one_action_chain (ar_hash, region)
327790075Sobrien     htab_t ar_hash;
327890075Sobrien     struct eh_region *region;
327990075Sobrien{
328090075Sobrien  struct eh_region *c;
328190075Sobrien  int next;
328250397Sobrien
328390075Sobrien  /* If we've reached the top of the region chain, then we have
328490075Sobrien     no actions, and require no landing pad.  */
328590075Sobrien  if (region == NULL)
328690075Sobrien    return -1;
328790075Sobrien
328890075Sobrien  switch (region->type)
328990075Sobrien    {
329090075Sobrien    case ERT_CLEANUP:
329190075Sobrien      /* A cleanup adds a zero filter to the beginning of the chain, but
329290075Sobrien	 there are special cases to look out for.  If there are *only*
329390075Sobrien	 cleanups along a path, then it compresses to a zero action.
329490075Sobrien	 Further, if there are multiple cleanups along a path, we only
329590075Sobrien	 need to represent one of them, as that is enough to trigger
329690075Sobrien	 entry to the landing pad at runtime.  */
329790075Sobrien      next = collect_one_action_chain (ar_hash, region->outer);
329890075Sobrien      if (next <= 0)
329990075Sobrien	return 0;
330090075Sobrien      for (c = region->outer; c ; c = c->outer)
330190075Sobrien	if (c->type == ERT_CLEANUP)
330290075Sobrien	  return next;
330390075Sobrien      return add_action_record (ar_hash, 0, next);
330490075Sobrien
330590075Sobrien    case ERT_TRY:
330690075Sobrien      /* Process the associated catch regions in reverse order.
330790075Sobrien	 If there's a catch-all handler, then we don't need to
330890075Sobrien	 search outer regions.  Use a magic -3 value to record
330990075Sobrien	 that we haven't done the outer search.  */
331090075Sobrien      next = -3;
331190075Sobrien      for (c = region->u.try.last_catch; c ; c = c->u.catch.prev_catch)
331290075Sobrien	{
331390075Sobrien	  if (c->u.catch.type_list == NULL)
331490075Sobrien	    {
331590075Sobrien	      /* Retrieve the filter from the head of the filter list
331690075Sobrien		 where we have stored it (see assign_filter_values).  */
331790075Sobrien	      int filter
331890075Sobrien		= TREE_INT_CST_LOW (TREE_VALUE (c->u.catch.filter_list));
331990075Sobrien
332090075Sobrien	      next = add_action_record (ar_hash, filter, 0);
332190075Sobrien	    }
332290075Sobrien	  else
332390075Sobrien	    {
332490075Sobrien	      /* Once the outer search is done, trigger an action record for
332590075Sobrien                 each filter we have.  */
332690075Sobrien	      tree flt_node;
332790075Sobrien
332890075Sobrien	      if (next == -3)
332990075Sobrien		{
333090075Sobrien		  next = collect_one_action_chain (ar_hash, region->outer);
333190075Sobrien
333290075Sobrien		  /* If there is no next action, terminate the chain.  */
333390075Sobrien		  if (next == -1)
333490075Sobrien		    next = 0;
333590075Sobrien		  /* If all outer actions are cleanups or must_not_throw,
333690075Sobrien		     we'll have no action record for it, since we had wanted
333790075Sobrien		     to encode these states in the call-site record directly.
333890075Sobrien		     Add a cleanup action to the chain to catch these.  */
333990075Sobrien		  else if (next <= 0)
334090075Sobrien		    next = add_action_record (ar_hash, 0, 0);
334190075Sobrien		}
334290075Sobrien
334390075Sobrien	      flt_node = c->u.catch.filter_list;
334490075Sobrien	      for (; flt_node; flt_node = TREE_CHAIN (flt_node))
334590075Sobrien		{
334690075Sobrien		  int filter = TREE_INT_CST_LOW (TREE_VALUE (flt_node));
334790075Sobrien		  next = add_action_record (ar_hash, filter, next);
334890075Sobrien		}
334990075Sobrien	    }
335090075Sobrien	}
335190075Sobrien      return next;
335290075Sobrien
335390075Sobrien    case ERT_ALLOWED_EXCEPTIONS:
335490075Sobrien      /* An exception specification adds its filter to the
335590075Sobrien	 beginning of the chain.  */
335690075Sobrien      next = collect_one_action_chain (ar_hash, region->outer);
335790075Sobrien      return add_action_record (ar_hash, region->u.allowed.filter,
335890075Sobrien				next < 0 ? 0 : next);
335990075Sobrien
336090075Sobrien    case ERT_MUST_NOT_THROW:
336190075Sobrien      /* A must-not-throw region with no inner handlers or cleanups
336290075Sobrien	 requires no call-site entry.  Note that this differs from
336390075Sobrien	 the no handler or cleanup case in that we do require an lsda
336490075Sobrien	 to be generated.  Return a magic -2 value to record this.  */
336590075Sobrien      return -2;
336690075Sobrien
336790075Sobrien    case ERT_CATCH:
336890075Sobrien    case ERT_THROW:
336990075Sobrien      /* CATCH regions are handled in TRY above.  THROW regions are
337090075Sobrien	 for optimization information only and produce no output.  */
337190075Sobrien      return collect_one_action_chain (ar_hash, region->outer);
337290075Sobrien
337390075Sobrien    default:
337490075Sobrien      abort ();
337590075Sobrien    }
337690075Sobrien}
337790075Sobrien
337890075Sobrienstatic int
337990075Sobrienadd_call_site (landing_pad, action)
338090075Sobrien     rtx landing_pad;
338190075Sobrien     int action;
338250397Sobrien{
338390075Sobrien  struct call_site_record *data = cfun->eh->call_site_data;
338490075Sobrien  int used = cfun->eh->call_site_data_used;
338590075Sobrien  int size = cfun->eh->call_site_data_size;
338650397Sobrien
338790075Sobrien  if (used >= size)
338890075Sobrien    {
338990075Sobrien      size = (size ? size * 2 : 64);
339090075Sobrien      data = (struct call_site_record *)
339190075Sobrien	xrealloc (data, sizeof (*data) * size);
339290075Sobrien      cfun->eh->call_site_data = data;
339390075Sobrien      cfun->eh->call_site_data_size = size;
339490075Sobrien    }
339590075Sobrien
339690075Sobrien  data[used].landing_pad = landing_pad;
339790075Sobrien  data[used].action = action;
339890075Sobrien
339990075Sobrien  cfun->eh->call_site_data_used = used + 1;
340090075Sobrien
340190075Sobrien  return used + call_site_base;
340250397Sobrien}
340350397Sobrien
340490075Sobrien/* Turn REG_EH_REGION notes back into NOTE_INSN_EH_REGION notes.
340590075Sobrien   The new note numbers will not refer to region numbers, but
340690075Sobrien   instead to call site entries.  */
340790075Sobrien
340852284Sobrienvoid
340990075Sobrienconvert_to_eh_region_ranges ()
341050397Sobrien{
341190075Sobrien  rtx insn, iter, note;
341290075Sobrien  htab_t ar_hash;
341390075Sobrien  int last_action = -3;
341490075Sobrien  rtx last_action_insn = NULL_RTX;
341590075Sobrien  rtx last_landing_pad = NULL_RTX;
341690075Sobrien  rtx first_no_action_insn = NULL_RTX;
341790075Sobrien  int call_site = 0;
341850397Sobrien
341990075Sobrien  if (USING_SJLJ_EXCEPTIONS || cfun->eh->region_tree == NULL)
342052284Sobrien    return;
342150397Sobrien
342290075Sobrien  VARRAY_UCHAR_INIT (cfun->eh->action_record_data, 64, "action_record_data");
342350397Sobrien
342490075Sobrien  ar_hash = htab_create (31, action_record_hash, action_record_eq, free);
342550397Sobrien
342690075Sobrien  for (iter = get_insns (); iter ; iter = NEXT_INSN (iter))
342790075Sobrien    if (INSN_P (iter))
342890075Sobrien      {
342990075Sobrien	struct eh_region *region;
343090075Sobrien	int this_action;
343190075Sobrien	rtx this_landing_pad;
343250397Sobrien
343390075Sobrien	insn = iter;
343490075Sobrien	if (GET_CODE (insn) == INSN
343590075Sobrien	    && GET_CODE (PATTERN (insn)) == SEQUENCE)
343690075Sobrien	  insn = XVECEXP (PATTERN (insn), 0, 0);
343750397Sobrien
343890075Sobrien	note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
343990075Sobrien	if (!note)
344090075Sobrien	  {
344190075Sobrien	    if (! (GET_CODE (insn) == CALL_INSN
344290075Sobrien		   || (flag_non_call_exceptions
344390075Sobrien		       && may_trap_p (PATTERN (insn)))))
344490075Sobrien	      continue;
344590075Sobrien	    this_action = -1;
344690075Sobrien	    region = NULL;
344790075Sobrien	  }
344890075Sobrien	else
344990075Sobrien	  {
345090075Sobrien	    if (INTVAL (XEXP (note, 0)) <= 0)
345190075Sobrien	      continue;
345290075Sobrien	    region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
345390075Sobrien	    this_action = collect_one_action_chain (ar_hash, region);
345490075Sobrien	  }
345550397Sobrien
345690075Sobrien	/* Existence of catch handlers, or must-not-throw regions
345790075Sobrien	   implies that an lsda is needed (even if empty).  */
345890075Sobrien	if (this_action != -1)
345990075Sobrien	  cfun->uses_eh_lsda = 1;
346050397Sobrien
346190075Sobrien	/* Delay creation of region notes for no-action regions
346290075Sobrien	   until we're sure that an lsda will be required.  */
346390075Sobrien	else if (last_action == -3)
346490075Sobrien	  {
346590075Sobrien	    first_no_action_insn = iter;
346690075Sobrien	    last_action = -1;
346790075Sobrien	  }
346850397Sobrien
346990075Sobrien	/* Cleanups and handlers may share action chains but not
347090075Sobrien	   landing pads.  Collect the landing pad for this region.  */
347190075Sobrien	if (this_action >= 0)
347290075Sobrien	  {
347390075Sobrien	    struct eh_region *o;
347490075Sobrien	    for (o = region; ! o->landing_pad ; o = o->outer)
347590075Sobrien	      continue;
347690075Sobrien	    this_landing_pad = o->landing_pad;
347790075Sobrien	  }
347890075Sobrien	else
347990075Sobrien	  this_landing_pad = NULL_RTX;
348050397Sobrien
348190075Sobrien	/* Differing actions or landing pads implies a change in call-site
348290075Sobrien	   info, which implies some EH_REGION note should be emitted.  */
348390075Sobrien	if (last_action != this_action
348490075Sobrien	    || last_landing_pad != this_landing_pad)
348590075Sobrien	  {
348690075Sobrien	    /* If we'd not seen a previous action (-3) or the previous
348790075Sobrien	       action was must-not-throw (-2), then we do not need an
348890075Sobrien	       end note.  */
348990075Sobrien	    if (last_action >= -1)
349090075Sobrien	      {
349190075Sobrien		/* If we delayed the creation of the begin, do it now.  */
349290075Sobrien		if (first_no_action_insn)
349390075Sobrien		  {
349490075Sobrien		    call_site = add_call_site (NULL_RTX, 0);
349590075Sobrien		    note = emit_note_before (NOTE_INSN_EH_REGION_BEG,
349690075Sobrien					     first_no_action_insn);
349790075Sobrien		    NOTE_EH_HANDLER (note) = call_site;
349890075Sobrien		    first_no_action_insn = NULL_RTX;
349990075Sobrien		  }
350050397Sobrien
350190075Sobrien		note = emit_note_after (NOTE_INSN_EH_REGION_END,
350290075Sobrien					last_action_insn);
350390075Sobrien		NOTE_EH_HANDLER (note) = call_site;
350490075Sobrien	      }
350552284Sobrien
350690075Sobrien	    /* If the new action is must-not-throw, then no region notes
350790075Sobrien	       are created.  */
350890075Sobrien	    if (this_action >= -1)
350990075Sobrien	      {
351090075Sobrien		call_site = add_call_site (this_landing_pad,
351190075Sobrien					   this_action < 0 ? 0 : this_action);
351290075Sobrien		note = emit_note_before (NOTE_INSN_EH_REGION_BEG, iter);
351390075Sobrien		NOTE_EH_HANDLER (note) = call_site;
351490075Sobrien	      }
351552284Sobrien
351690075Sobrien	    last_action = this_action;
351790075Sobrien	    last_landing_pad = this_landing_pad;
351890075Sobrien	  }
351990075Sobrien	last_action_insn = iter;
352090075Sobrien      }
352152284Sobrien
352290075Sobrien  if (last_action >= -1 && ! first_no_action_insn)
352390075Sobrien    {
352490075Sobrien      note = emit_note_after (NOTE_INSN_EH_REGION_END, last_action_insn);
352590075Sobrien      NOTE_EH_HANDLER (note) = call_site;
352690075Sobrien    }
352752284Sobrien
352890075Sobrien  htab_delete (ar_hash);
352950397Sobrien}
353090075Sobrien
353150397Sobrien
353290075Sobrienstatic void
353390075Sobrienpush_uleb128 (data_area, value)
353490075Sobrien     varray_type *data_area;
353590075Sobrien     unsigned int value;
353690075Sobrien{
353790075Sobrien  do
353890075Sobrien    {
353990075Sobrien      unsigned char byte = value & 0x7f;
354090075Sobrien      value >>= 7;
354190075Sobrien      if (value)
354290075Sobrien	byte |= 0x80;
354390075Sobrien      VARRAY_PUSH_UCHAR (*data_area, byte);
354490075Sobrien    }
354590075Sobrien  while (value);
354690075Sobrien}
354750397Sobrien
354890075Sobrienstatic void
354990075Sobrienpush_sleb128 (data_area, value)
355090075Sobrien     varray_type *data_area;
355190075Sobrien     int value;
355290075Sobrien{
355390075Sobrien  unsigned char byte;
355490075Sobrien  int more;
355550397Sobrien
355690075Sobrien  do
355790075Sobrien    {
355890075Sobrien      byte = value & 0x7f;
355990075Sobrien      value >>= 7;
356090075Sobrien      more = ! ((value == 0 && (byte & 0x40) == 0)
356190075Sobrien		|| (value == -1 && (byte & 0x40) != 0));
356290075Sobrien      if (more)
356390075Sobrien	byte |= 0x80;
356490075Sobrien      VARRAY_PUSH_UCHAR (*data_area, byte);
356590075Sobrien    }
356690075Sobrien  while (more);
356790075Sobrien}
356850397Sobrien
356990075Sobrien
357090075Sobrien#ifndef HAVE_AS_LEB128
357190075Sobrienstatic int
357290075Sobriendw2_size_of_call_site_table ()
357350397Sobrien{
357490075Sobrien  int n = cfun->eh->call_site_data_used;
357590075Sobrien  int size = n * (4 + 4 + 4);
357690075Sobrien  int i;
357750397Sobrien
357890075Sobrien  for (i = 0; i < n; ++i)
357950397Sobrien    {
358090075Sobrien      struct call_site_record *cs = &cfun->eh->call_site_data[i];
358190075Sobrien      size += size_of_uleb128 (cs->action);
358250397Sobrien    }
358390075Sobrien
358490075Sobrien  return size;
358550397Sobrien}
358650397Sobrien
358790075Sobrienstatic int
358890075Sobriensjlj_size_of_call_site_table ()
358990075Sobrien{
359090075Sobrien  int n = cfun->eh->call_site_data_used;
359190075Sobrien  int size = 0;
359290075Sobrien  int i;
359350397Sobrien
359490075Sobrien  for (i = 0; i < n; ++i)
359590075Sobrien    {
359690075Sobrien      struct call_site_record *cs = &cfun->eh->call_site_data[i];
359790075Sobrien      size += size_of_uleb128 (INTVAL (cs->landing_pad));
359890075Sobrien      size += size_of_uleb128 (cs->action);
359990075Sobrien    }
360090075Sobrien
360190075Sobrien  return size;
360290075Sobrien}
360390075Sobrien#endif
360490075Sobrien
360590075Sobrienstatic void
360690075Sobriendw2_output_call_site_table ()
360750397Sobrien{
360890075Sobrien  const char *const function_start_lab
360990075Sobrien    = IDENTIFIER_POINTER (current_function_func_begin_label);
361090075Sobrien  int n = cfun->eh->call_site_data_used;
361190075Sobrien  int i;
361250397Sobrien
361390075Sobrien  for (i = 0; i < n; ++i)
361450397Sobrien    {
361590075Sobrien      struct call_site_record *cs = &cfun->eh->call_site_data[i];
361690075Sobrien      char reg_start_lab[32];
361790075Sobrien      char reg_end_lab[32];
361890075Sobrien      char landing_pad_lab[32];
361990075Sobrien
362090075Sobrien      ASM_GENERATE_INTERNAL_LABEL (reg_start_lab, "LEHB", call_site_base + i);
362190075Sobrien      ASM_GENERATE_INTERNAL_LABEL (reg_end_lab, "LEHE", call_site_base + i);
362290075Sobrien
362390075Sobrien      if (cs->landing_pad)
362490075Sobrien	ASM_GENERATE_INTERNAL_LABEL (landing_pad_lab, "L",
362590075Sobrien				     CODE_LABEL_NUMBER (cs->landing_pad));
362690075Sobrien
362790075Sobrien      /* ??? Perhaps use insn length scaling if the assembler supports
362890075Sobrien	 generic arithmetic.  */
362990075Sobrien      /* ??? Perhaps use attr_length to choose data1 or data2 instead of
363090075Sobrien	 data4 if the function is small enough.  */
363190075Sobrien#ifdef HAVE_AS_LEB128
363290075Sobrien      dw2_asm_output_delta_uleb128 (reg_start_lab, function_start_lab,
363390075Sobrien				    "region %d start", i);
363490075Sobrien      dw2_asm_output_delta_uleb128 (reg_end_lab, reg_start_lab,
363590075Sobrien				    "length");
363690075Sobrien      if (cs->landing_pad)
363790075Sobrien	dw2_asm_output_delta_uleb128 (landing_pad_lab, function_start_lab,
363890075Sobrien				      "landing pad");
363990075Sobrien      else
364090075Sobrien	dw2_asm_output_data_uleb128 (0, "landing pad");
364190075Sobrien#else
364290075Sobrien      dw2_asm_output_delta (4, reg_start_lab, function_start_lab,
364390075Sobrien			    "region %d start", i);
364490075Sobrien      dw2_asm_output_delta (4, reg_end_lab, reg_start_lab, "length");
364590075Sobrien      if (cs->landing_pad)
364690075Sobrien	dw2_asm_output_delta (4, landing_pad_lab, function_start_lab,
364790075Sobrien			      "landing pad");
364890075Sobrien      else
364990075Sobrien	dw2_asm_output_data (4, 0, "landing pad");
365090075Sobrien#endif
365190075Sobrien      dw2_asm_output_data_uleb128 (cs->action, "action");
365250397Sobrien    }
365390075Sobrien
365490075Sobrien  call_site_base += n;
365550397Sobrien}
365650397Sobrien
365790075Sobrienstatic void
365890075Sobriensjlj_output_call_site_table ()
365990075Sobrien{
366090075Sobrien  int n = cfun->eh->call_site_data_used;
366190075Sobrien  int i;
366250397Sobrien
366390075Sobrien  for (i = 0; i < n; ++i)
366490075Sobrien    {
366590075Sobrien      struct call_site_record *cs = &cfun->eh->call_site_data[i];
366690075Sobrien
366790075Sobrien      dw2_asm_output_data_uleb128 (INTVAL (cs->landing_pad),
366890075Sobrien				   "region %d landing pad", i);
366990075Sobrien      dw2_asm_output_data_uleb128 (cs->action, "action");
367090075Sobrien    }
367190075Sobrien
367290075Sobrien  call_site_base += n;
367390075Sobrien}
367490075Sobrien
367590075Sobrienvoid
367690075Sobrienoutput_function_exception_table ()
367750397Sobrien{
367890075Sobrien  int tt_format, cs_format, lp_format, i, n;
367990075Sobrien#ifdef HAVE_AS_LEB128
368090075Sobrien  char ttype_label[32];
368190075Sobrien  char cs_after_size_label[32];
368290075Sobrien  char cs_end_label[32];
368390075Sobrien#else
368490075Sobrien  int call_site_len;
368590075Sobrien#endif
368690075Sobrien  int have_tt_data;
368790075Sobrien  int funcdef_number;
368890075Sobrien  int tt_format_size = 0;
368950397Sobrien
369090075Sobrien  /* Not all functions need anything.  */
369190075Sobrien  if (! cfun->uses_eh_lsda)
369250397Sobrien    return;
369350397Sobrien
369490075Sobrien  funcdef_number = (USING_SJLJ_EXCEPTIONS
369590075Sobrien		    ? sjlj_funcdef_number
369690075Sobrien		    : current_funcdef_number);
369750397Sobrien
369890075Sobrien#ifdef IA64_UNWIND_INFO
369990075Sobrien  fputs ("\t.personality\t", asm_out_file);
370090075Sobrien  output_addr_const (asm_out_file, eh_personality_libfunc);
370190075Sobrien  fputs ("\n\t.handlerdata\n", asm_out_file);
370290075Sobrien  /* Note that varasm still thinks we're in the function's code section.
370390075Sobrien     The ".endp" directive that will immediately follow will take us back.  */
370490075Sobrien#else
370590075Sobrien  (*targetm.asm_out.exception_section) ();
370690075Sobrien#endif
370750397Sobrien
370890075Sobrien  have_tt_data = (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) > 0
370990075Sobrien		  || VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) > 0);
371050397Sobrien
371190075Sobrien  /* Indicate the format of the @TType entries.  */
371290075Sobrien  if (! have_tt_data)
371390075Sobrien    tt_format = DW_EH_PE_omit;
371490075Sobrien  else
371590075Sobrien    {
371690075Sobrien      tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
371790075Sobrien#ifdef HAVE_AS_LEB128
371890075Sobrien      ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT", funcdef_number);
371990075Sobrien#endif
372090075Sobrien      tt_format_size = size_of_encoded_value (tt_format);
372150397Sobrien
372290075Sobrien      assemble_align (tt_format_size * BITS_PER_UNIT);
372390075Sobrien    }
372450397Sobrien
372590075Sobrien  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LLSDA", funcdef_number);
372650397Sobrien
372790075Sobrien  /* The LSDA header.  */
372850397Sobrien
372990075Sobrien  /* Indicate the format of the landing pad start pointer.  An omitted
373090075Sobrien     field implies @LPStart == @Start.  */
373190075Sobrien  /* Currently we always put @LPStart == @Start.  This field would
373290075Sobrien     be most useful in moving the landing pads completely out of
373390075Sobrien     line to another section, but it could also be used to minimize
373490075Sobrien     the size of uleb128 landing pad offsets.  */
373590075Sobrien  lp_format = DW_EH_PE_omit;
373690075Sobrien  dw2_asm_output_data (1, lp_format, "@LPStart format (%s)",
373790075Sobrien		       eh_data_format_name (lp_format));
373850397Sobrien
373990075Sobrien  /* @LPStart pointer would go here.  */
374050397Sobrien
374190075Sobrien  dw2_asm_output_data (1, tt_format, "@TType format (%s)",
374290075Sobrien		       eh_data_format_name (tt_format));
374350397Sobrien
374490075Sobrien#ifndef HAVE_AS_LEB128
374590075Sobrien  if (USING_SJLJ_EXCEPTIONS)
374690075Sobrien    call_site_len = sjlj_size_of_call_site_table ();
374790075Sobrien  else
374890075Sobrien    call_site_len = dw2_size_of_call_site_table ();
374990075Sobrien#endif
375090075Sobrien
375190075Sobrien  /* A pc-relative 4-byte displacement to the @TType data.  */
375290075Sobrien  if (have_tt_data)
375390075Sobrien    {
375490075Sobrien#ifdef HAVE_AS_LEB128
375590075Sobrien      char ttype_after_disp_label[32];
375690075Sobrien      ASM_GENERATE_INTERNAL_LABEL (ttype_after_disp_label, "LLSDATTD",
375790075Sobrien				   funcdef_number);
375890075Sobrien      dw2_asm_output_delta_uleb128 (ttype_label, ttype_after_disp_label,
375990075Sobrien				    "@TType base offset");
376090075Sobrien      ASM_OUTPUT_LABEL (asm_out_file, ttype_after_disp_label);
376190075Sobrien#else
376290075Sobrien      /* Ug.  Alignment queers things.  */
376390075Sobrien      unsigned int before_disp, after_disp, last_disp, disp;
376490075Sobrien
376590075Sobrien      before_disp = 1 + 1;
376690075Sobrien      after_disp = (1 + size_of_uleb128 (call_site_len)
376790075Sobrien		    + call_site_len
376890075Sobrien		    + VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data)
376990075Sobrien		    + (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data)
377090075Sobrien		       * tt_format_size));
377190075Sobrien
377290075Sobrien      disp = after_disp;
377390075Sobrien      do
377490075Sobrien	{
377590075Sobrien	  unsigned int disp_size, pad;
377690075Sobrien
377790075Sobrien	  last_disp = disp;
377890075Sobrien	  disp_size = size_of_uleb128 (disp);
377990075Sobrien	  pad = before_disp + disp_size + after_disp;
378090075Sobrien	  if (pad % tt_format_size)
378190075Sobrien	    pad = tt_format_size - (pad % tt_format_size);
378290075Sobrien	  else
378390075Sobrien	    pad = 0;
378490075Sobrien	  disp = after_disp + pad;
378590075Sobrien	}
378690075Sobrien      while (disp != last_disp);
378790075Sobrien
378890075Sobrien      dw2_asm_output_data_uleb128 (disp, "@TType base offset");
378990075Sobrien#endif
379090075Sobrien    }
379190075Sobrien
379290075Sobrien  /* Indicate the format of the call-site offsets.  */
379390075Sobrien#ifdef HAVE_AS_LEB128
379490075Sobrien  cs_format = DW_EH_PE_uleb128;
379590075Sobrien#else
379690075Sobrien  cs_format = DW_EH_PE_udata4;
379790075Sobrien#endif
379890075Sobrien  dw2_asm_output_data (1, cs_format, "call-site format (%s)",
379990075Sobrien		       eh_data_format_name (cs_format));
380090075Sobrien
380190075Sobrien#ifdef HAVE_AS_LEB128
380290075Sobrien  ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label, "LLSDACSB",
380390075Sobrien			       funcdef_number);
380490075Sobrien  ASM_GENERATE_INTERNAL_LABEL (cs_end_label, "LLSDACSE",
380590075Sobrien			       funcdef_number);
380690075Sobrien  dw2_asm_output_delta_uleb128 (cs_end_label, cs_after_size_label,
380790075Sobrien				"Call-site table length");
380890075Sobrien  ASM_OUTPUT_LABEL (asm_out_file, cs_after_size_label);
380990075Sobrien  if (USING_SJLJ_EXCEPTIONS)
381090075Sobrien    sjlj_output_call_site_table ();
381190075Sobrien  else
381290075Sobrien    dw2_output_call_site_table ();
381390075Sobrien  ASM_OUTPUT_LABEL (asm_out_file, cs_end_label);
381490075Sobrien#else
381590075Sobrien  dw2_asm_output_data_uleb128 (call_site_len,"Call-site table length");
381690075Sobrien  if (USING_SJLJ_EXCEPTIONS)
381790075Sobrien    sjlj_output_call_site_table ();
381890075Sobrien  else
381990075Sobrien    dw2_output_call_site_table ();
382090075Sobrien#endif
382190075Sobrien
382290075Sobrien  /* ??? Decode and interpret the data for flag_debug_asm.  */
382390075Sobrien  n = VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data);
382490075Sobrien  for (i = 0; i < n; ++i)
382590075Sobrien    dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->action_record_data, i),
382690075Sobrien			 (i ? NULL : "Action record table"));
382790075Sobrien
382890075Sobrien  if (have_tt_data)
382990075Sobrien    assemble_align (tt_format_size * BITS_PER_UNIT);
383090075Sobrien
383190075Sobrien  i = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data);
383290075Sobrien  while (i-- > 0)
383390075Sobrien    {
383490075Sobrien      tree type = VARRAY_TREE (cfun->eh->ttype_data, i);
383590075Sobrien      rtx value;
383690075Sobrien
383790075Sobrien      if (type == NULL_TREE)
383890075Sobrien	type = integer_zero_node;
383990075Sobrien      else
384090075Sobrien	type = lookup_type_for_runtime (type);
384190075Sobrien
384290075Sobrien      value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
384390075Sobrien      if (tt_format == DW_EH_PE_absptr || tt_format == DW_EH_PE_aligned)
384490075Sobrien	assemble_integer (value, tt_format_size,
384590075Sobrien			  tt_format_size * BITS_PER_UNIT, 1);
384690075Sobrien      else
384790075Sobrien        dw2_asm_output_encoded_addr_rtx (tt_format, value, NULL);
384890075Sobrien    }
384990075Sobrien
385090075Sobrien#ifdef HAVE_AS_LEB128
385190075Sobrien  if (have_tt_data)
385290075Sobrien      ASM_OUTPUT_LABEL (asm_out_file, ttype_label);
385390075Sobrien#endif
385490075Sobrien
385590075Sobrien  /* ??? Decode and interpret the data for flag_debug_asm.  */
385690075Sobrien  n = VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data);
385790075Sobrien  for (i = 0; i < n; ++i)
385890075Sobrien    dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->ehspec_data, i),
385990075Sobrien			 (i ? NULL : "Exception specification table"));
386090075Sobrien
386190075Sobrien  function_section (current_function_decl);
386290075Sobrien
386390075Sobrien  if (USING_SJLJ_EXCEPTIONS)
386490075Sobrien    sjlj_funcdef_number += 1;
386550397Sobrien}
3866