except.c revision 117395
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"
73117395Skan#include "langhooks.h"
7450397Sobrien
7590075Sobrien/* Provide defaults for stuff that may not be defined when using
7690075Sobrien   sjlj exceptions.  */
7790075Sobrien#ifndef EH_RETURN_DATA_REGNO
7890075Sobrien#define EH_RETURN_DATA_REGNO(N) INVALID_REGNUM
7990075Sobrien#endif
8050397Sobrien
8150397Sobrien
8290075Sobrien/* Nonzero means enable synchronous exceptions for non-call instructions.  */
8390075Sobrienint flag_non_call_exceptions;
8450397Sobrien
8590075Sobrien/* Protect cleanup actions with must-not-throw regions, with a call
8690075Sobrien   to the given failure handler.  */
8790075Sobrientree (*lang_protect_cleanup_actions) PARAMS ((void));
8850397Sobrien
8990075Sobrien/* Return true if type A catches type B.  */
9090075Sobrienint (*lang_eh_type_covers) PARAMS ((tree a, tree b));
9150397Sobrien
9290075Sobrien/* Map a type to a runtime object to match type.  */
9390075Sobrientree (*lang_eh_runtime_type) PARAMS ((tree));
9450397Sobrien
9596263Sobrien/* A hash table of label to region number.  */
9650397Sobrien
97117395Skanstruct ehl_map_entry GTY(())
9896263Sobrien{
9996263Sobrien  rtx label;
10096263Sobrien  struct eh_region *region;
10196263Sobrien};
10296263Sobrien
10390075Sobrienstatic int call_site_base;
104117395Skanstatic GTY ((param_is (union tree_node)))
105117395Skan  htab_t type_to_runtime_map;
10650397Sobrien
10790075Sobrien/* Describe the SjLj_Function_Context structure.  */
108117395Skanstatic GTY(()) 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.  */
116117395Skanstruct eh_region GTY(())
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
12896263Sobrien  /* When a region is deleted, its parents inherit the REG_EH_REGION
12996263Sobrien     numbers already assigned.  */
13096263Sobrien  bitmap aka;
13196263Sobrien
13290075Sobrien  /* Each region does exactly one thing.  */
13390075Sobrien  enum eh_region_type
13490075Sobrien  {
13590075Sobrien    ERT_UNKNOWN = 0,
13690075Sobrien    ERT_CLEANUP,
13790075Sobrien    ERT_TRY,
13890075Sobrien    ERT_CATCH,
13990075Sobrien    ERT_ALLOWED_EXCEPTIONS,
14090075Sobrien    ERT_MUST_NOT_THROW,
14190075Sobrien    ERT_THROW,
14290075Sobrien    ERT_FIXUP
14390075Sobrien  } type;
14450397Sobrien
14590075Sobrien  /* Holds the action to perform based on the preceding type.  */
146117395Skan  union eh_region_u {
14790075Sobrien    /* A list of catch blocks, a surrounding try block,
14890075Sobrien       and the label for continuing after a catch.  */
149117395Skan    struct eh_region_u_try {
15090075Sobrien      struct eh_region *catch;
15190075Sobrien      struct eh_region *last_catch;
15290075Sobrien      struct eh_region *prev_try;
15390075Sobrien      rtx continue_label;
154117395Skan    } GTY ((tag ("ERT_TRY"))) try;
15550397Sobrien
15690075Sobrien    /* The list through the catch handlers, the list of type objects
15790075Sobrien       matched, and the list of associated filters.  */
158117395Skan    struct eh_region_u_catch {
15990075Sobrien      struct eh_region *next_catch;
16090075Sobrien      struct eh_region *prev_catch;
16190075Sobrien      tree type_list;
16290075Sobrien      tree filter_list;
163117395Skan    } GTY ((tag ("ERT_CATCH"))) catch;
16450397Sobrien
16590075Sobrien    /* A tree_list of allowed types.  */
166117395Skan    struct eh_region_u_allowed {
16790075Sobrien      tree type_list;
16890075Sobrien      int filter;
169117395Skan    } GTY ((tag ("ERT_ALLOWED_EXCEPTIONS"))) allowed;
17050397Sobrien
17190075Sobrien    /* The type given by a call to "throw foo();", or discovered
17290075Sobrien       for a throw.  */
173117395Skan    struct eh_region_u_throw {
17490075Sobrien      tree type;
175117395Skan    } GTY ((tag ("ERT_THROW"))) throw;
17650397Sobrien
17790075Sobrien    /* Retain the cleanup expression even after expansion so that
17890075Sobrien       we can match up fixup regions.  */
179117395Skan    struct eh_region_u_cleanup {
18090075Sobrien      tree exp;
181117395Skan      struct eh_region *prev_try;
182117395Skan    } GTY ((tag ("ERT_CLEANUP"))) cleanup;
18350397Sobrien
18490075Sobrien    /* The real region (by expression and by pointer) that fixup code
18590075Sobrien       should live in.  */
186117395Skan    struct eh_region_u_fixup {
18790075Sobrien      tree cleanup_exp;
18890075Sobrien      struct eh_region *real_region;
189117395Skan    } GTY ((tag ("ERT_FIXUP"))) fixup;
190117395Skan  } GTY ((desc ("%0.type"))) u;
19150397Sobrien
19290075Sobrien  /* Entry point for this region's handler before landing pads are built.  */
19390075Sobrien  rtx label;
19450397Sobrien
19590075Sobrien  /* Entry point for this region's handler from the runtime eh library.  */
19690075Sobrien  rtx landing_pad;
19750397Sobrien
19890075Sobrien  /* Entry point for this region's handler from an inner region.  */
19990075Sobrien  rtx post_landing_pad;
20050397Sobrien
20190075Sobrien  /* The RESX insn for handing off control to the next outermost handler,
20290075Sobrien     if appropriate.  */
20390075Sobrien  rtx resume;
204117395Skan
205117395Skan  /* True if something in this region may throw.  */
206117395Skan  unsigned may_contain_throw : 1;
20790075Sobrien};
20850397Sobrien
209117395Skanstruct call_site_record GTY(())
210117395Skan{
211117395Skan  rtx landing_pad;
212117395Skan  int action;
213117395Skan};
214117395Skan
21590075Sobrien/* Used to save exception status for each function.  */
216117395Skanstruct eh_status GTY(())
21790075Sobrien{
21890075Sobrien  /* The tree of all regions for this function.  */
21990075Sobrien  struct eh_region *region_tree;
22050397Sobrien
22190075Sobrien  /* The same information as an indexable array.  */
222117395Skan  struct eh_region ** GTY ((length ("%h.last_region_number"))) region_array;
22350397Sobrien
22490075Sobrien  /* The most recently open region.  */
22590075Sobrien  struct eh_region *cur_region;
22650397Sobrien
22790075Sobrien  /* This is the region for which we are processing catch blocks.  */
22890075Sobrien  struct eh_region *try_region;
22950397Sobrien
23090075Sobrien  rtx filter;
23190075Sobrien  rtx exc_ptr;
23250397Sobrien
23390075Sobrien  int built_landing_pads;
23490075Sobrien  int last_region_number;
23550397Sobrien
23690075Sobrien  varray_type ttype_data;
23790075Sobrien  varray_type ehspec_data;
23890075Sobrien  varray_type action_record_data;
23950397Sobrien
240117395Skan  htab_t GTY ((param_is (struct ehl_map_entry))) exception_handler_label_map;
241117395Skan
242117395Skan  struct call_site_record * GTY ((length ("%h.call_site_data_used")))
243117395Skan    call_site_data;
24490075Sobrien  int call_site_data_used;
24590075Sobrien  int call_site_data_size;
24650397Sobrien
24790075Sobrien  rtx ehr_stackadj;
24890075Sobrien  rtx ehr_handler;
24990075Sobrien  rtx ehr_label;
25050397Sobrien
25190075Sobrien  rtx sjlj_fc;
25290075Sobrien  rtx sjlj_exit_after;
25390075Sobrien};
25450397Sobrien
25590075Sobrien
25690075Sobrienstatic int t2r_eq				PARAMS ((const PTR,
25790075Sobrien							 const PTR));
25890075Sobrienstatic hashval_t t2r_hash			PARAMS ((const PTR));
25990075Sobrienstatic void add_type_for_runtime		PARAMS ((tree));
26090075Sobrienstatic tree lookup_type_for_runtime		PARAMS ((tree));
26150397Sobrien
26290075Sobrienstatic struct eh_region *expand_eh_region_end	PARAMS ((void));
26350397Sobrien
26490075Sobrienstatic rtx get_exception_filter			PARAMS ((struct function *));
26550397Sobrien
26690075Sobrienstatic void collect_eh_region_array		PARAMS ((void));
26790075Sobrienstatic void resolve_fixup_regions		PARAMS ((void));
26890075Sobrienstatic void remove_fixup_regions		PARAMS ((void));
26990075Sobrienstatic void remove_unreachable_regions		PARAMS ((rtx));
27090075Sobrienstatic void convert_from_eh_region_ranges_1	PARAMS ((rtx *, int *, int));
27150397Sobrien
27290075Sobrienstatic struct eh_region *duplicate_eh_region_1	PARAMS ((struct eh_region *,
27390075Sobrien						     struct inline_remap *));
27490075Sobrienstatic void duplicate_eh_region_2		PARAMS ((struct eh_region *,
27590075Sobrien							 struct eh_region **));
27690075Sobrienstatic int ttypes_filter_eq			PARAMS ((const PTR,
27790075Sobrien							 const PTR));
27890075Sobrienstatic hashval_t ttypes_filter_hash		PARAMS ((const PTR));
27990075Sobrienstatic int ehspec_filter_eq			PARAMS ((const PTR,
28090075Sobrien							 const PTR));
28190075Sobrienstatic hashval_t ehspec_filter_hash		PARAMS ((const PTR));
28290075Sobrienstatic int add_ttypes_entry			PARAMS ((htab_t, tree));
28390075Sobrienstatic int add_ehspec_entry			PARAMS ((htab_t, htab_t,
28490075Sobrien							 tree));
28590075Sobrienstatic void assign_filter_values		PARAMS ((void));
28690075Sobrienstatic void build_post_landing_pads		PARAMS ((void));
28790075Sobrienstatic void connect_post_landing_pads		PARAMS ((void));
28890075Sobrienstatic void dw2_build_landing_pads		PARAMS ((void));
28950397Sobrien
29090075Sobrienstruct sjlj_lp_info;
29190075Sobrienstatic bool sjlj_find_directly_reachable_regions
29290075Sobrien     PARAMS ((struct sjlj_lp_info *));
29390075Sobrienstatic void sjlj_assign_call_site_values
29490075Sobrien     PARAMS ((rtx, struct sjlj_lp_info *));
29590075Sobrienstatic void sjlj_mark_call_sites
29690075Sobrien     PARAMS ((struct sjlj_lp_info *));
29790075Sobrienstatic void sjlj_emit_function_enter		PARAMS ((rtx));
29890075Sobrienstatic void sjlj_emit_function_exit		PARAMS ((void));
29990075Sobrienstatic void sjlj_emit_dispatch_table
30090075Sobrien     PARAMS ((rtx, struct sjlj_lp_info *));
30190075Sobrienstatic void sjlj_build_landing_pads		PARAMS ((void));
30250397Sobrien
30396263Sobrienstatic hashval_t ehl_hash			PARAMS ((const PTR));
30496263Sobrienstatic int ehl_eq				PARAMS ((const PTR,
30596263Sobrien							 const PTR));
30696263Sobrienstatic void add_ehl_entry			PARAMS ((rtx,
30796263Sobrien							 struct eh_region *));
30890075Sobrienstatic void remove_exception_handler_label	PARAMS ((rtx));
30990075Sobrienstatic void remove_eh_handler			PARAMS ((struct eh_region *));
31096263Sobrienstatic int for_each_eh_label_1			PARAMS ((PTR *, PTR));
31150397Sobrien
31290075Sobrienstruct reachable_info;
31350397Sobrien
31490075Sobrien/* The return value of reachable_next_level.  */
31590075Sobrienenum reachable_code
31690075Sobrien{
31790075Sobrien  /* The given exception is not processed by the given region.  */
31890075Sobrien  RNL_NOT_CAUGHT,
31990075Sobrien  /* The given exception may need processing by the given region.  */
32090075Sobrien  RNL_MAYBE_CAUGHT,
32190075Sobrien  /* The given exception is completely processed by the given region.  */
32290075Sobrien  RNL_CAUGHT,
32390075Sobrien  /* The given exception is completely processed by the runtime.  */
32490075Sobrien  RNL_BLOCKED
32590075Sobrien};
32650397Sobrien
32790075Sobrienstatic int check_handled			PARAMS ((tree, tree));
32890075Sobrienstatic void add_reachable_handler
32990075Sobrien     PARAMS ((struct reachable_info *, struct eh_region *,
33090075Sobrien	      struct eh_region *));
33190075Sobrienstatic enum reachable_code reachable_next_level
33290075Sobrien     PARAMS ((struct eh_region *, tree, struct reachable_info *));
33350397Sobrien
33490075Sobrienstatic int action_record_eq			PARAMS ((const PTR,
33590075Sobrien							 const PTR));
33690075Sobrienstatic hashval_t action_record_hash		PARAMS ((const PTR));
33790075Sobrienstatic int add_action_record			PARAMS ((htab_t, int, int));
33890075Sobrienstatic int collect_one_action_chain		PARAMS ((htab_t,
33990075Sobrien							 struct eh_region *));
34090075Sobrienstatic int add_call_site			PARAMS ((rtx, int));
34150397Sobrien
34290075Sobrienstatic void push_uleb128			PARAMS ((varray_type *,
34390075Sobrien							 unsigned int));
34490075Sobrienstatic void push_sleb128			PARAMS ((varray_type *, int));
34590075Sobrien#ifndef HAVE_AS_LEB128
34690075Sobrienstatic int dw2_size_of_call_site_table		PARAMS ((void));
34790075Sobrienstatic int sjlj_size_of_call_site_table		PARAMS ((void));
34890075Sobrien#endif
34990075Sobrienstatic void dw2_output_call_site_table		PARAMS ((void));
35090075Sobrienstatic void sjlj_output_call_site_table		PARAMS ((void));
35150397Sobrien
35290075Sobrien
35390075Sobrien/* Routine to see if exception handling is turned on.
354117395Skan   DO_WARN is nonzero if we want to inform the user that exception
35590075Sobrien   handling is turned off.
35650397Sobrien
35790075Sobrien   This is used to ensure that -fexceptions has been specified if the
35890075Sobrien   compiler tries to use any exception-specific functions.  */
35950397Sobrien
36090075Sobrienint
36190075Sobriendoing_eh (do_warn)
36290075Sobrien     int do_warn;
36390075Sobrien{
36490075Sobrien  if (! flag_exceptions)
36590075Sobrien    {
36690075Sobrien      static int warned = 0;
36790075Sobrien      if (! warned && do_warn)
36890075Sobrien	{
36990075Sobrien	  error ("exception handling disabled, use -fexceptions to enable");
37090075Sobrien	  warned = 1;
37190075Sobrien	}
37290075Sobrien      return 0;
37390075Sobrien    }
37490075Sobrien  return 1;
37590075Sobrien}
37650397Sobrien
37790075Sobrien
37890075Sobrienvoid
37990075Sobrieninit_eh ()
38090075Sobrien{
38190075Sobrien  if (! flag_exceptions)
38290075Sobrien    return;
38350397Sobrien
384117395Skan  type_to_runtime_map = htab_create_ggc (31, t2r_hash, t2r_eq, NULL);
38550397Sobrien
38690075Sobrien  /* Create the SjLj_Function_Context structure.  This should match
38790075Sobrien     the definition in unwind-sjlj.c.  */
38890075Sobrien  if (USING_SJLJ_EXCEPTIONS)
38990075Sobrien    {
39090075Sobrien      tree f_jbuf, f_per, f_lsda, f_prev, f_cs, f_data, tmp;
39150397Sobrien
392117395Skan      sjlj_fc_type_node = (*lang_hooks.types.make_type) (RECORD_TYPE);
39350397Sobrien
39490075Sobrien      f_prev = build_decl (FIELD_DECL, get_identifier ("__prev"),
39590075Sobrien			   build_pointer_type (sjlj_fc_type_node));
39690075Sobrien      DECL_FIELD_CONTEXT (f_prev) = sjlj_fc_type_node;
39750397Sobrien
39890075Sobrien      f_cs = build_decl (FIELD_DECL, get_identifier ("__call_site"),
39990075Sobrien			 integer_type_node);
40090075Sobrien      DECL_FIELD_CONTEXT (f_cs) = sjlj_fc_type_node;
40150397Sobrien
40290075Sobrien      tmp = build_index_type (build_int_2 (4 - 1, 0));
403117395Skan      tmp = build_array_type ((*lang_hooks.types.type_for_mode) (word_mode, 1),
404117395Skan			      tmp);
40590075Sobrien      f_data = build_decl (FIELD_DECL, get_identifier ("__data"), tmp);
40690075Sobrien      DECL_FIELD_CONTEXT (f_data) = sjlj_fc_type_node;
40750397Sobrien
40890075Sobrien      f_per = build_decl (FIELD_DECL, get_identifier ("__personality"),
40990075Sobrien			  ptr_type_node);
41090075Sobrien      DECL_FIELD_CONTEXT (f_per) = sjlj_fc_type_node;
41150397Sobrien
41290075Sobrien      f_lsda = build_decl (FIELD_DECL, get_identifier ("__lsda"),
41390075Sobrien			   ptr_type_node);
41490075Sobrien      DECL_FIELD_CONTEXT (f_lsda) = sjlj_fc_type_node;
41550397Sobrien
41690075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP
41790075Sobrien#ifdef JMP_BUF_SIZE
41890075Sobrien      tmp = build_int_2 (JMP_BUF_SIZE - 1, 0);
41990075Sobrien#else
42090075Sobrien      /* Should be large enough for most systems, if it is not,
42190075Sobrien	 JMP_BUF_SIZE should be defined with the proper value.  It will
42290075Sobrien	 also tend to be larger than necessary for most systems, a more
42390075Sobrien	 optimal port will define JMP_BUF_SIZE.  */
42490075Sobrien      tmp = build_int_2 (FIRST_PSEUDO_REGISTER + 2 - 1, 0);
42590075Sobrien#endif
42690075Sobrien#else
42790075Sobrien      /* This is 2 for builtin_setjmp, plus whatever the target requires
42890075Sobrien	 via STACK_SAVEAREA_MODE (SAVE_NONLOCAL).  */
42990075Sobrien      tmp = build_int_2 ((GET_MODE_SIZE (STACK_SAVEAREA_MODE (SAVE_NONLOCAL))
43090075Sobrien			  / GET_MODE_SIZE (Pmode)) + 2 - 1, 0);
43190075Sobrien#endif
43290075Sobrien      tmp = build_index_type (tmp);
43390075Sobrien      tmp = build_array_type (ptr_type_node, tmp);
43490075Sobrien      f_jbuf = build_decl (FIELD_DECL, get_identifier ("__jbuf"), tmp);
43590075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP
43690075Sobrien      /* We don't know what the alignment requirements of the
43790075Sobrien	 runtime's jmp_buf has.  Overestimate.  */
43890075Sobrien      DECL_ALIGN (f_jbuf) = BIGGEST_ALIGNMENT;
43990075Sobrien      DECL_USER_ALIGN (f_jbuf) = 1;
44090075Sobrien#endif
44190075Sobrien      DECL_FIELD_CONTEXT (f_jbuf) = sjlj_fc_type_node;
44250397Sobrien
44390075Sobrien      TYPE_FIELDS (sjlj_fc_type_node) = f_prev;
44490075Sobrien      TREE_CHAIN (f_prev) = f_cs;
44590075Sobrien      TREE_CHAIN (f_cs) = f_data;
44690075Sobrien      TREE_CHAIN (f_data) = f_per;
44790075Sobrien      TREE_CHAIN (f_per) = f_lsda;
44890075Sobrien      TREE_CHAIN (f_lsda) = f_jbuf;
44950397Sobrien
45090075Sobrien      layout_type (sjlj_fc_type_node);
45150397Sobrien
45290075Sobrien      /* Cache the interesting field offsets so that we have
45390075Sobrien	 easy access from rtl.  */
45490075Sobrien      sjlj_fc_call_site_ofs
45590075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_cs), 1)
45690075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_cs), 1) / BITS_PER_UNIT);
45790075Sobrien      sjlj_fc_data_ofs
45890075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_data), 1)
45990075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_data), 1) / BITS_PER_UNIT);
46090075Sobrien      sjlj_fc_personality_ofs
46190075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_per), 1)
46290075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_per), 1) / BITS_PER_UNIT);
46390075Sobrien      sjlj_fc_lsda_ofs
46490075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_lsda), 1)
46590075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_lsda), 1) / BITS_PER_UNIT);
46690075Sobrien      sjlj_fc_jbuf_ofs
46790075Sobrien	= (tree_low_cst (DECL_FIELD_OFFSET (f_jbuf), 1)
46890075Sobrien	   + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_jbuf), 1) / BITS_PER_UNIT);
46990075Sobrien    }
47090075Sobrien}
47150397Sobrien
47290075Sobrienvoid
47390075Sobrieninit_eh_for_function ()
47490075Sobrien{
475117395Skan  cfun->eh = (struct eh_status *)
476117395Skan    ggc_alloc_cleared (sizeof (struct eh_status));
47790075Sobrien}
47890075Sobrien
47990075Sobrien/* Start an exception handling region.  All instructions emitted
48090075Sobrien   after this point are considered to be part of the region until
48190075Sobrien   expand_eh_region_end is invoked.  */
48250397Sobrien
48390075Sobrienvoid
48490075Sobrienexpand_eh_region_start ()
48590075Sobrien{
48690075Sobrien  struct eh_region *new_region;
48790075Sobrien  struct eh_region *cur_region;
48890075Sobrien  rtx note;
48952284Sobrien
49090075Sobrien  if (! doing_eh (0))
49190075Sobrien    return;
49252284Sobrien
49390075Sobrien  /* Insert a new blank region as a leaf in the tree.  */
494117395Skan  new_region = (struct eh_region *) ggc_alloc_cleared (sizeof (*new_region));
49590075Sobrien  cur_region = cfun->eh->cur_region;
49690075Sobrien  new_region->outer = cur_region;
49790075Sobrien  if (cur_region)
49890075Sobrien    {
49990075Sobrien      new_region->next_peer = cur_region->inner;
50090075Sobrien      cur_region->inner = new_region;
50190075Sobrien    }
50290075Sobrien  else
50390075Sobrien    {
50490075Sobrien      new_region->next_peer = cfun->eh->region_tree;
50590075Sobrien      cfun->eh->region_tree = new_region;
50690075Sobrien    }
50790075Sobrien  cfun->eh->cur_region = new_region;
50852284Sobrien
50990075Sobrien  /* Create a note marking the start of this region.  */
51090075Sobrien  new_region->region_number = ++cfun->eh->last_region_number;
51190075Sobrien  note = emit_note (NULL, NOTE_INSN_EH_REGION_BEG);
51290075Sobrien  NOTE_EH_HANDLER (note) = new_region->region_number;
51390075Sobrien}
51452284Sobrien
51590075Sobrien/* Common code to end a region.  Returns the region just ended.  */
51652284Sobrien
51790075Sobrienstatic struct eh_region *
51890075Sobrienexpand_eh_region_end ()
51990075Sobrien{
52090075Sobrien  struct eh_region *cur_region = cfun->eh->cur_region;
52190075Sobrien  rtx note;
52252284Sobrien
52390075Sobrien  /* Create a note marking the end of this region.  */
52490075Sobrien  note = emit_note (NULL, NOTE_INSN_EH_REGION_END);
52590075Sobrien  NOTE_EH_HANDLER (note) = cur_region->region_number;
52652284Sobrien
52790075Sobrien  /* Pop.  */
52890075Sobrien  cfun->eh->cur_region = cur_region->outer;
52952284Sobrien
53090075Sobrien  return cur_region;
53190075Sobrien}
53250397Sobrien
53390075Sobrien/* End an exception handling region for a cleanup.  HANDLER is an
53490075Sobrien   expression to expand for the cleanup.  */
53550397Sobrien
53690075Sobrienvoid
53790075Sobrienexpand_eh_region_end_cleanup (handler)
53890075Sobrien     tree handler;
53952284Sobrien{
54090075Sobrien  struct eh_region *region;
54190075Sobrien  tree protect_cleanup_actions;
54290075Sobrien  rtx around_label;
54390075Sobrien  rtx data_save[2];
54452284Sobrien
54590075Sobrien  if (! doing_eh (0))
54690075Sobrien    return;
54752284Sobrien
54890075Sobrien  region = expand_eh_region_end ();
54990075Sobrien  region->type = ERT_CLEANUP;
55090075Sobrien  region->label = gen_label_rtx ();
55190075Sobrien  region->u.cleanup.exp = handler;
552117395Skan  region->u.cleanup.prev_try = cfun->eh->try_region;
55352284Sobrien
55490075Sobrien  around_label = gen_label_rtx ();
55590075Sobrien  emit_jump (around_label);
55652284Sobrien
55790075Sobrien  emit_label (region->label);
55850397Sobrien
559117395Skan  if (flag_non_call_exceptions || region->may_contain_throw)
560117395Skan    {
561117395Skan      /* Give the language a chance to specify an action to be taken if an
562117395Skan	 exception is thrown that would propagate out of the HANDLER.  */
563117395Skan      protect_cleanup_actions
564117395Skan	= (lang_protect_cleanup_actions
565117395Skan	   ? (*lang_protect_cleanup_actions) ()
566117395Skan	   : NULL_TREE);
56750397Sobrien
568117395Skan      if (protect_cleanup_actions)
569117395Skan	expand_eh_region_start ();
57050397Sobrien
571117395Skan      /* In case this cleanup involves an inline destructor with a try block in
572117395Skan	 it, we need to save the EH return data registers around it.  */
573117395Skan      data_save[0] = gen_reg_rtx (ptr_mode);
574117395Skan      emit_move_insn (data_save[0], get_exception_pointer (cfun));
575117395Skan      data_save[1] = gen_reg_rtx (word_mode);
576117395Skan      emit_move_insn (data_save[1], get_exception_filter (cfun));
57750397Sobrien
578117395Skan      expand_expr (handler, const0_rtx, VOIDmode, 0);
57950397Sobrien
580117395Skan      emit_move_insn (cfun->eh->exc_ptr, data_save[0]);
581117395Skan      emit_move_insn (cfun->eh->filter, data_save[1]);
58250397Sobrien
583117395Skan      if (protect_cleanup_actions)
584117395Skan	expand_eh_region_end_must_not_throw (protect_cleanup_actions);
58550397Sobrien
586117395Skan      /* We need any stack adjustment complete before the around_label.  */
587117395Skan      do_pending_stack_adjust ();
588117395Skan    }
58990075Sobrien
59090075Sobrien  /* We delay the generation of the _Unwind_Resume until we generate
59190075Sobrien     landing pads.  We emit a marker here so as to get good control
59290075Sobrien     flow data in the meantime.  */
59390075Sobrien  region->resume
59490075Sobrien    = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
59590075Sobrien  emit_barrier ();
59690075Sobrien
59790075Sobrien  emit_label (around_label);
59850397Sobrien}
59950397Sobrien
60090075Sobrien/* End an exception handling region for a try block, and prepares
60190075Sobrien   for subsequent calls to expand_start_catch.  */
60250397Sobrien
60390075Sobrienvoid
60490075Sobrienexpand_start_all_catch ()
60550397Sobrien{
60690075Sobrien  struct eh_region *region;
60750397Sobrien
60890075Sobrien  if (! doing_eh (1))
60990075Sobrien    return;
61050397Sobrien
61190075Sobrien  region = expand_eh_region_end ();
61290075Sobrien  region->type = ERT_TRY;
61390075Sobrien  region->u.try.prev_try = cfun->eh->try_region;
61490075Sobrien  region->u.try.continue_label = gen_label_rtx ();
61550397Sobrien
61690075Sobrien  cfun->eh->try_region = region;
61790075Sobrien
61890075Sobrien  emit_jump (region->u.try.continue_label);
61950397Sobrien}
62050397Sobrien
62190075Sobrien/* Begin a catch clause.  TYPE is the type caught, a list of such types, or
62290075Sobrien   null if this is a catch-all clause. Providing a type list enables to
62390075Sobrien   associate the catch region with potentially several exception types, which
62490075Sobrien   is useful e.g. for Ada.  */
62550397Sobrien
62690075Sobrienvoid
62790075Sobrienexpand_start_catch (type_or_list)
62890075Sobrien     tree type_or_list;
62950397Sobrien{
63090075Sobrien  struct eh_region *t, *c, *l;
63190075Sobrien  tree type_list;
63250397Sobrien
63390075Sobrien  if (! doing_eh (0))
63490075Sobrien    return;
63590075Sobrien
63690075Sobrien  type_list = type_or_list;
63790075Sobrien
63890075Sobrien  if (type_or_list)
63990075Sobrien    {
64090075Sobrien      /* Ensure to always end up with a type list to normalize further
64190075Sobrien         processing, then register each type against the runtime types
64290075Sobrien         map.  */
64390075Sobrien      tree type_node;
64490075Sobrien
64590075Sobrien      if (TREE_CODE (type_or_list) != TREE_LIST)
646117395Skan	type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE);
64790075Sobrien
64890075Sobrien      type_node = type_list;
64990075Sobrien      for (; type_node; type_node = TREE_CHAIN (type_node))
650117395Skan	add_type_for_runtime (TREE_VALUE (type_node));
65190075Sobrien    }
65290075Sobrien
65390075Sobrien  expand_eh_region_start ();
65490075Sobrien
65590075Sobrien  t = cfun->eh->try_region;
65690075Sobrien  c = cfun->eh->cur_region;
65790075Sobrien  c->type = ERT_CATCH;
65890075Sobrien  c->u.catch.type_list = type_list;
65990075Sobrien  c->label = gen_label_rtx ();
66090075Sobrien
66190075Sobrien  l = t->u.try.last_catch;
66290075Sobrien  c->u.catch.prev_catch = l;
66390075Sobrien  if (l)
66490075Sobrien    l->u.catch.next_catch = c;
66552284Sobrien  else
66690075Sobrien    t->u.try.catch = c;
66790075Sobrien  t->u.try.last_catch = c;
66850397Sobrien
66990075Sobrien  emit_label (c->label);
67050397Sobrien}
67150397Sobrien
67290075Sobrien/* End a catch clause.  Control will resume after the try/catch block.  */
67390075Sobrien
67490075Sobrienvoid
67590075Sobrienexpand_end_catch ()
67650397Sobrien{
67790075Sobrien  struct eh_region *try_region, *catch_region;
67850397Sobrien
67990075Sobrien  if (! doing_eh (0))
68090075Sobrien    return;
68150397Sobrien
68290075Sobrien  catch_region = expand_eh_region_end ();
68390075Sobrien  try_region = cfun->eh->try_region;
68450397Sobrien
68590075Sobrien  emit_jump (try_region->u.try.continue_label);
68650397Sobrien}
68750397Sobrien
68890075Sobrien/* End a sequence of catch handlers for a try block.  */
68950397Sobrien
69090075Sobrienvoid
69190075Sobrienexpand_end_all_catch ()
69250397Sobrien{
69390075Sobrien  struct eh_region *try_region;
69450397Sobrien
69590075Sobrien  if (! doing_eh (0))
69690075Sobrien    return;
69750397Sobrien
69890075Sobrien  try_region = cfun->eh->try_region;
69990075Sobrien  cfun->eh->try_region = try_region->u.try.prev_try;
70090075Sobrien
70190075Sobrien  emit_label (try_region->u.try.continue_label);
70250397Sobrien}
70350397Sobrien
70490075Sobrien/* End an exception region for an exception type filter.  ALLOWED is a
70590075Sobrien   TREE_LIST of types to be matched by the runtime.  FAILURE is an
70690075Sobrien   expression to invoke if a mismatch occurs.
70750397Sobrien
70890075Sobrien   ??? We could use these semantics for calls to rethrow, too; if we can
70990075Sobrien   see the surrounding catch clause, we know that the exception we're
71090075Sobrien   rethrowing satisfies the "filter" of the catch type.  */
71190075Sobrien
71290075Sobrienvoid
71390075Sobrienexpand_eh_region_end_allowed (allowed, failure)
71490075Sobrien     tree allowed, failure;
71550397Sobrien{
71690075Sobrien  struct eh_region *region;
71790075Sobrien  rtx around_label;
71850397Sobrien
71990075Sobrien  if (! doing_eh (0))
72090075Sobrien    return;
72150397Sobrien
72290075Sobrien  region = expand_eh_region_end ();
72390075Sobrien  region->type = ERT_ALLOWED_EXCEPTIONS;
72490075Sobrien  region->u.allowed.type_list = allowed;
72590075Sobrien  region->label = gen_label_rtx ();
72650397Sobrien
72790075Sobrien  for (; allowed ; allowed = TREE_CHAIN (allowed))
72890075Sobrien    add_type_for_runtime (TREE_VALUE (allowed));
72950397Sobrien
73090075Sobrien  /* We must emit the call to FAILURE here, so that if this function
73190075Sobrien     throws a different exception, that it will be processed by the
73290075Sobrien     correct region.  */
73390075Sobrien
73490075Sobrien  around_label = gen_label_rtx ();
73590075Sobrien  emit_jump (around_label);
73690075Sobrien
73790075Sobrien  emit_label (region->label);
73890075Sobrien  expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL);
73990075Sobrien  /* We must adjust the stack before we reach the AROUND_LABEL because
74090075Sobrien     the call to FAILURE does not occur on all paths to the
74190075Sobrien     AROUND_LABEL.  */
74290075Sobrien  do_pending_stack_adjust ();
74390075Sobrien
74490075Sobrien  emit_label (around_label);
74550397Sobrien}
74650397Sobrien
74790075Sobrien/* End an exception region for a must-not-throw filter.  FAILURE is an
74890075Sobrien   expression invoke if an uncaught exception propagates this far.
74990075Sobrien
75090075Sobrien   This is conceptually identical to expand_eh_region_end_allowed with
75190075Sobrien   an empty allowed list (if you passed "std::terminate" instead of
75290075Sobrien   "__cxa_call_unexpected"), but they are represented differently in
75390075Sobrien   the C++ LSDA.  */
75490075Sobrien
75590075Sobrienvoid
75690075Sobrienexpand_eh_region_end_must_not_throw (failure)
75790075Sobrien     tree failure;
75850397Sobrien{
75990075Sobrien  struct eh_region *region;
76090075Sobrien  rtx around_label;
76174722Sobrien
76290075Sobrien  if (! doing_eh (0))
76390075Sobrien    return;
76474722Sobrien
76590075Sobrien  region = expand_eh_region_end ();
76690075Sobrien  region->type = ERT_MUST_NOT_THROW;
76790075Sobrien  region->label = gen_label_rtx ();
76874722Sobrien
76990075Sobrien  /* We must emit the call to FAILURE here, so that if this function
77090075Sobrien     throws a different exception, that it will be processed by the
77190075Sobrien     correct region.  */
77290075Sobrien
77390075Sobrien  around_label = gen_label_rtx ();
77490075Sobrien  emit_jump (around_label);
77590075Sobrien
77690075Sobrien  emit_label (region->label);
77790075Sobrien  expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL);
77890075Sobrien
77990075Sobrien  emit_label (around_label);
78050397Sobrien}
78150397Sobrien
78290075Sobrien/* End an exception region for a throw.  No handling goes on here,
78390075Sobrien   but it's the easiest way for the front-end to indicate what type
78490075Sobrien   is being thrown.  */
78590075Sobrien
78690075Sobrienvoid
78790075Sobrienexpand_eh_region_end_throw (type)
78890075Sobrien     tree type;
78950397Sobrien{
79090075Sobrien  struct eh_region *region;
79150397Sobrien
79290075Sobrien  if (! doing_eh (0))
79390075Sobrien    return;
79450397Sobrien
79590075Sobrien  region = expand_eh_region_end ();
79690075Sobrien  region->type = ERT_THROW;
79790075Sobrien  region->u.throw.type = type;
79890075Sobrien}
79950397Sobrien
80090075Sobrien/* End a fixup region.  Within this region the cleanups for the immediately
80190075Sobrien   enclosing region are _not_ run.  This is used for goto cleanup to avoid
80290075Sobrien   destroying an object twice.
80350397Sobrien
80490075Sobrien   This would be an extraordinarily simple prospect, were it not for the
80590075Sobrien   fact that we don't actually know what the immediately enclosing region
80690075Sobrien   is.  This surprising fact is because expand_cleanups is currently
80790075Sobrien   generating a sequence that it will insert somewhere else.  We collect
80890075Sobrien   the proper notion of "enclosing" in convert_from_eh_region_ranges.  */
80950397Sobrien
81090075Sobrienvoid
81190075Sobrienexpand_eh_region_end_fixup (handler)
81290075Sobrien     tree handler;
81350397Sobrien{
81490075Sobrien  struct eh_region *fixup;
81550397Sobrien
81690075Sobrien  if (! doing_eh (0))
81790075Sobrien    return;
81890075Sobrien
81990075Sobrien  fixup = expand_eh_region_end ();
82090075Sobrien  fixup->type = ERT_FIXUP;
82190075Sobrien  fixup->u.fixup.cleanup_exp = handler;
82250397Sobrien}
82350397Sobrien
824117395Skan/* Note that the current EH region (if any) may contain a throw, or a
825117395Skan   call to a function which itself may contain a throw.  */
826117395Skan
827117395Skanvoid
828117395Skannote_eh_region_may_contain_throw ()
829117395Skan{
830117395Skan  struct eh_region *region;
831117395Skan
832117395Skan  region = cfun->eh->cur_region;
833117395Skan  while (region && !region->may_contain_throw)
834117395Skan    {
835117395Skan      region->may_contain_throw = 1;
836117395Skan      region = region->outer;
837117395Skan    }
838117395Skan}
839117395Skan
84090075Sobrien/* Return an rtl expression for a pointer to the exception object
84190075Sobrien   within a handler.  */
84250397Sobrien
84390075Sobrienrtx
84490075Sobrienget_exception_pointer (fun)
84590075Sobrien     struct function *fun;
84650397Sobrien{
84790075Sobrien  rtx exc_ptr = fun->eh->exc_ptr;
84890075Sobrien  if (fun == cfun && ! exc_ptr)
84950397Sobrien    {
850117395Skan      exc_ptr = gen_reg_rtx (ptr_mode);
85190075Sobrien      fun->eh->exc_ptr = exc_ptr;
85250397Sobrien    }
85390075Sobrien  return exc_ptr;
85450397Sobrien}
85550397Sobrien
85690075Sobrien/* Return an rtl expression for the exception dispatch filter
85790075Sobrien   within a handler.  */
85850397Sobrien
85990075Sobrienstatic rtx
86090075Sobrienget_exception_filter (fun)
86190075Sobrien     struct function *fun;
86250397Sobrien{
86390075Sobrien  rtx filter = fun->eh->filter;
86490075Sobrien  if (fun == cfun && ! filter)
86550397Sobrien    {
86690075Sobrien      filter = gen_reg_rtx (word_mode);
86790075Sobrien      fun->eh->filter = filter;
86850397Sobrien    }
86990075Sobrien  return filter;
87050397Sobrien}
87190075Sobrien
87290075Sobrien/* This section is for the exception handling specific optimization pass.  */
87350397Sobrien
87490075Sobrien/* Random access the exception region tree.  It's just as simple to
87590075Sobrien   collect the regions this way as in expand_eh_region_start, but
87690075Sobrien   without having to realloc memory.  */
87790075Sobrien
87890075Sobrienstatic void
87990075Sobriencollect_eh_region_array ()
88050397Sobrien{
88190075Sobrien  struct eh_region **array, *i;
88250397Sobrien
88390075Sobrien  i = cfun->eh->region_tree;
88490075Sobrien  if (! i)
88590075Sobrien    return;
88650397Sobrien
887117395Skan  array = ggc_alloc_cleared ((cfun->eh->last_region_number + 1)
888117395Skan			     * sizeof (*array));
88990075Sobrien  cfun->eh->region_array = array;
89050397Sobrien
89190075Sobrien  while (1)
89290075Sobrien    {
89390075Sobrien      array[i->region_number] = i;
89450397Sobrien
89590075Sobrien      /* If there are sub-regions, process them.  */
89690075Sobrien      if (i->inner)
89790075Sobrien	i = i->inner;
89890075Sobrien      /* If there are peers, process them.  */
89990075Sobrien      else if (i->next_peer)
90090075Sobrien	i = i->next_peer;
90190075Sobrien      /* Otherwise, step back up the tree to the next peer.  */
90290075Sobrien      else
90390075Sobrien	{
90490075Sobrien	  do {
90590075Sobrien	    i = i->outer;
90690075Sobrien	    if (i == NULL)
90790075Sobrien	      return;
90890075Sobrien	  } while (i->next_peer == NULL);
90990075Sobrien	  i = i->next_peer;
91090075Sobrien	}
91190075Sobrien    }
91290075Sobrien}
91350397Sobrien
91490075Sobrienstatic void
91590075Sobrienresolve_fixup_regions ()
91650397Sobrien{
91790075Sobrien  int i, j, n = cfun->eh->last_region_number;
91850397Sobrien
91990075Sobrien  for (i = 1; i <= n; ++i)
92090075Sobrien    {
92190075Sobrien      struct eh_region *fixup = cfun->eh->region_array[i];
92290075Sobrien      struct eh_region *cleanup = 0;
92350397Sobrien
92490075Sobrien      if (! fixup || fixup->type != ERT_FIXUP)
92590075Sobrien	continue;
92650397Sobrien
92790075Sobrien      for (j = 1; j <= n; ++j)
92890075Sobrien	{
92990075Sobrien	  cleanup = cfun->eh->region_array[j];
93090075Sobrien	  if (cleanup->type == ERT_CLEANUP
93190075Sobrien	      && cleanup->u.cleanup.exp == fixup->u.fixup.cleanup_exp)
93290075Sobrien	    break;
93390075Sobrien	}
93490075Sobrien      if (j > n)
93590075Sobrien	abort ();
93690075Sobrien
93790075Sobrien      fixup->u.fixup.real_region = cleanup->outer;
93890075Sobrien    }
93950397Sobrien}
94050397Sobrien
94190075Sobrien/* Now that we've discovered what region actually encloses a fixup,
94290075Sobrien   we can shuffle pointers and remove them from the tree.  */
94350397Sobrien
94450397Sobrienstatic void
94590075Sobrienremove_fixup_regions ()
94650397Sobrien{
94790075Sobrien  int i;
94890075Sobrien  rtx insn, note;
94990075Sobrien  struct eh_region *fixup;
95090075Sobrien
95190075Sobrien  /* Walk the insn chain and adjust the REG_EH_REGION numbers
95290075Sobrien     for instructions referencing fixup regions.  This is only
95390075Sobrien     strictly necessary for fixup regions with no parent, but
95490075Sobrien     doesn't hurt to do it for all regions.  */
95590075Sobrien  for (insn = get_insns(); insn ; insn = NEXT_INSN (insn))
95690075Sobrien    if (INSN_P (insn)
95790075Sobrien	&& (note = find_reg_note (insn, REG_EH_REGION, NULL))
95890075Sobrien	&& INTVAL (XEXP (note, 0)) > 0
95990075Sobrien	&& (fixup = cfun->eh->region_array[INTVAL (XEXP (note, 0))])
96090075Sobrien	&& fixup->type == ERT_FIXUP)
96150397Sobrien      {
96290075Sobrien	if (fixup->u.fixup.real_region)
96390075Sobrien	  XEXP (note, 0) = GEN_INT (fixup->u.fixup.real_region->region_number);
96490075Sobrien	else
96590075Sobrien	  remove_note (insn, note);
96650397Sobrien      }
96750397Sobrien
96890075Sobrien  /* Remove the fixup regions from the tree.  */
96990075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
97090075Sobrien    {
97190075Sobrien      fixup = cfun->eh->region_array[i];
97290075Sobrien      if (! fixup)
97390075Sobrien	continue;
97450397Sobrien
97590075Sobrien      /* Allow GC to maybe free some memory.  */
97690075Sobrien      if (fixup->type == ERT_CLEANUP)
977117395Skan	fixup->u.cleanup.exp = NULL_TREE;
97850397Sobrien
97990075Sobrien      if (fixup->type != ERT_FIXUP)
98090075Sobrien	continue;
98150397Sobrien
98290075Sobrien      if (fixup->inner)
98390075Sobrien	{
98490075Sobrien	  struct eh_region *parent, *p, **pp;
98550397Sobrien
98690075Sobrien	  parent = fixup->u.fixup.real_region;
98752284Sobrien
98890075Sobrien	  /* Fix up the children's parent pointers; find the end of
98990075Sobrien	     the list.  */
99090075Sobrien	  for (p = fixup->inner; ; p = p->next_peer)
99190075Sobrien	    {
99290075Sobrien	      p->outer = parent;
99390075Sobrien	      if (! p->next_peer)
99490075Sobrien		break;
99590075Sobrien	    }
99650397Sobrien
99790075Sobrien	  /* In the tree of cleanups, only outer-inner ordering matters.
99890075Sobrien	     So link the children back in anywhere at the correct level.  */
99990075Sobrien	  if (parent)
100090075Sobrien	    pp = &parent->inner;
100190075Sobrien	  else
100290075Sobrien	    pp = &cfun->eh->region_tree;
100390075Sobrien	  p->next_peer = *pp;
100490075Sobrien	  *pp = fixup->inner;
100590075Sobrien	  fixup->inner = NULL;
100690075Sobrien	}
100790075Sobrien
100890075Sobrien      remove_eh_handler (fixup);
100950397Sobrien    }
101050397Sobrien}
101150397Sobrien
101290075Sobrien/* Remove all regions whose labels are not reachable from insns.  */
101352284Sobrien
101490075Sobrienstatic void
101590075Sobrienremove_unreachable_regions (insns)
101690075Sobrien     rtx insns;
101752284Sobrien{
101890075Sobrien  int i, *uid_region_num;
101990075Sobrien  bool *reachable;
102090075Sobrien  struct eh_region *r;
102190075Sobrien  rtx insn;
102252284Sobrien
102390075Sobrien  uid_region_num = xcalloc (get_max_uid (), sizeof(int));
102490075Sobrien  reachable = xcalloc (cfun->eh->last_region_number + 1, sizeof(bool));
102552284Sobrien
102690075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
102790075Sobrien    {
102890075Sobrien      r = cfun->eh->region_array[i];
102990075Sobrien      if (!r || r->region_number != i)
103090075Sobrien	continue;
103152284Sobrien
103290075Sobrien      if (r->resume)
1033117395Skan	{
103490075Sobrien	  if (uid_region_num[INSN_UID (r->resume)])
103590075Sobrien	    abort ();
103690075Sobrien	  uid_region_num[INSN_UID (r->resume)] = i;
1037117395Skan	}
103890075Sobrien      if (r->label)
1039117395Skan	{
104090075Sobrien	  if (uid_region_num[INSN_UID (r->label)])
104190075Sobrien	    abort ();
104290075Sobrien	  uid_region_num[INSN_UID (r->label)] = i;
1043117395Skan	}
104490075Sobrien      if (r->type == ERT_TRY && r->u.try.continue_label)
1045117395Skan	{
104690075Sobrien	  if (uid_region_num[INSN_UID (r->u.try.continue_label)])
104790075Sobrien	    abort ();
104890075Sobrien	  uid_region_num[INSN_UID (r->u.try.continue_label)] = i;
1049117395Skan	}
105052284Sobrien    }
105152284Sobrien
105290075Sobrien  for (insn = insns; insn; insn = NEXT_INSN (insn))
105390075Sobrien    reachable[uid_region_num[INSN_UID (insn)]] = true;
105450397Sobrien
105590075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
105650397Sobrien    {
105790075Sobrien      r = cfun->eh->region_array[i];
105890075Sobrien      if (r && r->region_number == i && !reachable[i])
105950397Sobrien	{
106090075Sobrien	  /* Don't remove ERT_THROW regions if their outer region
106190075Sobrien	     is reachable.  */
106290075Sobrien	  if (r->type == ERT_THROW
106390075Sobrien	      && r->outer
106490075Sobrien	      && reachable[r->outer->region_number])
106590075Sobrien	    continue;
106690075Sobrien
106790075Sobrien	  remove_eh_handler (r);
106850397Sobrien	}
106950397Sobrien    }
107090075Sobrien
107190075Sobrien  free (reachable);
107290075Sobrien  free (uid_region_num);
107350397Sobrien}
107450397Sobrien
107590075Sobrien/* Turn NOTE_INSN_EH_REGION notes into REG_EH_REGION notes for each
107690075Sobrien   can_throw instruction in the region.  */
107750397Sobrien
107890075Sobrienstatic void
107990075Sobrienconvert_from_eh_region_ranges_1 (pinsns, orig_sp, cur)
108090075Sobrien     rtx *pinsns;
108190075Sobrien     int *orig_sp;
108290075Sobrien     int cur;
108350397Sobrien{
108490075Sobrien  int *sp = orig_sp;
108590075Sobrien  rtx insn, next;
108650397Sobrien
108790075Sobrien  for (insn = *pinsns; insn ; insn = next)
108890075Sobrien    {
108990075Sobrien      next = NEXT_INSN (insn);
109090075Sobrien      if (GET_CODE (insn) == NOTE)
109190075Sobrien	{
109290075Sobrien	  int kind = NOTE_LINE_NUMBER (insn);
109390075Sobrien	  if (kind == NOTE_INSN_EH_REGION_BEG
109490075Sobrien	      || kind == NOTE_INSN_EH_REGION_END)
109590075Sobrien	    {
109690075Sobrien	      if (kind == NOTE_INSN_EH_REGION_BEG)
109790075Sobrien		{
109890075Sobrien		  struct eh_region *r;
109950397Sobrien
110090075Sobrien		  *sp++ = cur;
110190075Sobrien		  cur = NOTE_EH_HANDLER (insn);
110250397Sobrien
110390075Sobrien		  r = cfun->eh->region_array[cur];
110490075Sobrien		  if (r->type == ERT_FIXUP)
110590075Sobrien		    {
110690075Sobrien		      r = r->u.fixup.real_region;
110790075Sobrien		      cur = r ? r->region_number : 0;
110890075Sobrien		    }
110990075Sobrien		  else if (r->type == ERT_CATCH)
111090075Sobrien		    {
111190075Sobrien		      r = r->outer;
111290075Sobrien		      cur = r ? r->region_number : 0;
111390075Sobrien		    }
111490075Sobrien		}
111590075Sobrien	      else
111690075Sobrien		cur = *--sp;
111750397Sobrien
111890075Sobrien	      /* Removing the first insn of a CALL_PLACEHOLDER sequence
111990075Sobrien		 requires extra care to adjust sequence start.  */
112090075Sobrien	      if (insn == *pinsns)
112190075Sobrien		*pinsns = next;
112290075Sobrien	      remove_insn (insn);
112390075Sobrien	      continue;
112490075Sobrien	    }
112590075Sobrien	}
112690075Sobrien      else if (INSN_P (insn))
112790075Sobrien	{
112890075Sobrien	  if (cur > 0
112990075Sobrien	      && ! find_reg_note (insn, REG_EH_REGION, NULL_RTX)
113090075Sobrien	      /* Calls can always potentially throw exceptions, unless
113190075Sobrien		 they have a REG_EH_REGION note with a value of 0 or less.
113290075Sobrien		 Which should be the only possible kind so far.  */
113390075Sobrien	      && (GET_CODE (insn) == CALL_INSN
113490075Sobrien		  /* If we wanted exceptions for non-call insns, then
113590075Sobrien		     any may_trap_p instruction could throw.  */
113690075Sobrien		  || (flag_non_call_exceptions
113790075Sobrien		      && GET_CODE (PATTERN (insn)) != CLOBBER
113890075Sobrien		      && GET_CODE (PATTERN (insn)) != USE
113990075Sobrien		      && may_trap_p (PATTERN (insn)))))
114090075Sobrien	    {
114190075Sobrien	      REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION, GEN_INT (cur),
114290075Sobrien						  REG_NOTES (insn));
114390075Sobrien	    }
114450397Sobrien
114590075Sobrien	  if (GET_CODE (insn) == CALL_INSN
114690075Sobrien	      && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
114790075Sobrien	    {
114890075Sobrien	      convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 0),
114990075Sobrien					       sp, cur);
115090075Sobrien	      convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 1),
115190075Sobrien					       sp, cur);
115290075Sobrien	      convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 2),
115390075Sobrien					       sp, cur);
115490075Sobrien	    }
115590075Sobrien	}
115690075Sobrien    }
115750397Sobrien
115890075Sobrien  if (sp != orig_sp)
115990075Sobrien    abort ();
116050397Sobrien}
116150397Sobrien
116290075Sobrienvoid
116390075Sobrienconvert_from_eh_region_ranges ()
116450397Sobrien{
116590075Sobrien  int *stack;
116690075Sobrien  rtx insns;
116750397Sobrien
116890075Sobrien  collect_eh_region_array ();
116990075Sobrien  resolve_fixup_regions ();
117050397Sobrien
117190075Sobrien  stack = xmalloc (sizeof (int) * (cfun->eh->last_region_number + 1));
117290075Sobrien  insns = get_insns ();
117390075Sobrien  convert_from_eh_region_ranges_1 (&insns, stack, 0);
117490075Sobrien  free (stack);
117550397Sobrien
117690075Sobrien  remove_fixup_regions ();
117790075Sobrien  remove_unreachable_regions (insns);
117850397Sobrien}
117950397Sobrien
118096263Sobrienstatic void
118196263Sobrienadd_ehl_entry (label, region)
118296263Sobrien     rtx label;
118396263Sobrien     struct eh_region *region;
118496263Sobrien{
118596263Sobrien  struct ehl_map_entry **slot, *entry;
118696263Sobrien
118796263Sobrien  LABEL_PRESERVE_P (label) = 1;
118896263Sobrien
1189117395Skan  entry = (struct ehl_map_entry *) ggc_alloc (sizeof (*entry));
119096263Sobrien  entry->label = label;
119196263Sobrien  entry->region = region;
119296263Sobrien
119396263Sobrien  slot = (struct ehl_map_entry **)
1194117395Skan    htab_find_slot (cfun->eh->exception_handler_label_map, entry, INSERT);
119596263Sobrien
119696263Sobrien  /* Before landing pad creation, each exception handler has its own
119796263Sobrien     label.  After landing pad creation, the exception handlers may
119896263Sobrien     share landing pads.  This is ok, since maybe_remove_eh_handler
119996263Sobrien     only requires the 1-1 mapping before landing pad creation.  */
120096263Sobrien  if (*slot && !cfun->eh->built_landing_pads)
120196263Sobrien    abort ();
120296263Sobrien
120396263Sobrien  *slot = entry;
120496263Sobrien}
120596263Sobrien
120690075Sobrienvoid
120790075Sobrienfind_exception_handler_labels ()
120890075Sobrien{
120990075Sobrien  int i;
121050397Sobrien
1211117395Skan  if (cfun->eh->exception_handler_label_map)
1212117395Skan    htab_empty (cfun->eh->exception_handler_label_map);
121396263Sobrien  else
121496263Sobrien    {
121596263Sobrien      /* ??? The expansion factor here (3/2) must be greater than the htab
121696263Sobrien	 occupancy factor (4/3) to avoid unnecessary resizing.  */
1217117395Skan      cfun->eh->exception_handler_label_map
1218117395Skan        = htab_create_ggc (cfun->eh->last_region_number * 3 / 2,
1219117395Skan			   ehl_hash, ehl_eq, NULL);
122096263Sobrien    }
122150397Sobrien
122290075Sobrien  if (cfun->eh->region_tree == NULL)
122390075Sobrien    return;
122490075Sobrien
122590075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
122650397Sobrien    {
122790075Sobrien      struct eh_region *region = cfun->eh->region_array[i];
122890075Sobrien      rtx lab;
122950397Sobrien
123090075Sobrien      if (! region || region->region_number != i)
123190075Sobrien	continue;
123290075Sobrien      if (cfun->eh->built_landing_pads)
123390075Sobrien	lab = region->landing_pad;
123490075Sobrien      else
123590075Sobrien	lab = region->label;
123650397Sobrien
123790075Sobrien      if (lab)
123896263Sobrien	add_ehl_entry (lab, region);
123950397Sobrien    }
124090075Sobrien
124190075Sobrien  /* For sjlj exceptions, need the return label to remain live until
124290075Sobrien     after landing pad generation.  */
124390075Sobrien  if (USING_SJLJ_EXCEPTIONS && ! cfun->eh->built_landing_pads)
124496263Sobrien    add_ehl_entry (return_label, NULL);
124596263Sobrien}
124690075Sobrien
124796263Sobrienbool
124896263Sobriencurrent_function_has_exception_handlers ()
124996263Sobrien{
125096263Sobrien  int i;
125196263Sobrien
125296263Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
125396263Sobrien    {
125496263Sobrien      struct eh_region *region = cfun->eh->region_array[i];
125596263Sobrien
125696263Sobrien      if (! region || region->region_number != i)
125796263Sobrien	continue;
125896263Sobrien      if (region->type != ERT_THROW)
125996263Sobrien	return true;
126096263Sobrien    }
126196263Sobrien
126296263Sobrien  return false;
126350397Sobrien}
126490075Sobrien
126590075Sobrienstatic struct eh_region *
126690075Sobrienduplicate_eh_region_1 (o, map)
126790075Sobrien     struct eh_region *o;
126890075Sobrien     struct inline_remap *map;
126950397Sobrien{
127090075Sobrien  struct eh_region *n
1271117395Skan    = (struct eh_region *) ggc_alloc_cleared (sizeof (struct eh_region));
127250397Sobrien
127390075Sobrien  n->region_number = o->region_number + cfun->eh->last_region_number;
127490075Sobrien  n->type = o->type;
127550397Sobrien
127690075Sobrien  switch (n->type)
127790075Sobrien    {
127890075Sobrien    case ERT_CLEANUP:
127990075Sobrien    case ERT_MUST_NOT_THROW:
128090075Sobrien      break;
128150397Sobrien
128290075Sobrien    case ERT_TRY:
128390075Sobrien      if (o->u.try.continue_label)
128490075Sobrien	n->u.try.continue_label
128590075Sobrien	  = get_label_from_map (map,
128690075Sobrien				CODE_LABEL_NUMBER (o->u.try.continue_label));
128790075Sobrien      break;
128850397Sobrien
128990075Sobrien    case ERT_CATCH:
129090075Sobrien      n->u.catch.type_list = o->u.catch.type_list;
129190075Sobrien      break;
129250397Sobrien
129390075Sobrien    case ERT_ALLOWED_EXCEPTIONS:
129490075Sobrien      n->u.allowed.type_list = o->u.allowed.type_list;
129590075Sobrien      break;
129650397Sobrien
129790075Sobrien    case ERT_THROW:
129890075Sobrien      n->u.throw.type = o->u.throw.type;
129950397Sobrien
130090075Sobrien    default:
130190075Sobrien      abort ();
130290075Sobrien    }
130350397Sobrien
130490075Sobrien  if (o->label)
130590075Sobrien    n->label = get_label_from_map (map, CODE_LABEL_NUMBER (o->label));
130690075Sobrien  if (o->resume)
130790075Sobrien    {
130890075Sobrien      n->resume = map->insn_map[INSN_UID (o->resume)];
130990075Sobrien      if (n->resume == NULL)
131090075Sobrien	abort ();
131190075Sobrien    }
131250397Sobrien
131390075Sobrien  return n;
131450397Sobrien}
131550397Sobrien
131650397Sobrienstatic void
131790075Sobrienduplicate_eh_region_2 (o, n_array)
131890075Sobrien     struct eh_region *o;
131990075Sobrien     struct eh_region **n_array;
132050397Sobrien{
132190075Sobrien  struct eh_region *n = n_array[o->region_number];
132250397Sobrien
132390075Sobrien  switch (n->type)
132490075Sobrien    {
132590075Sobrien    case ERT_TRY:
132690075Sobrien      n->u.try.catch = n_array[o->u.try.catch->region_number];
132790075Sobrien      n->u.try.last_catch = n_array[o->u.try.last_catch->region_number];
132890075Sobrien      break;
132950397Sobrien
133090075Sobrien    case ERT_CATCH:
133190075Sobrien      if (o->u.catch.next_catch)
1332117395Skan	n->u.catch.next_catch = n_array[o->u.catch.next_catch->region_number];
133390075Sobrien      if (o->u.catch.prev_catch)
1334117395Skan	n->u.catch.prev_catch = n_array[o->u.catch.prev_catch->region_number];
133590075Sobrien      break;
133650397Sobrien
133790075Sobrien    default:
133890075Sobrien      break;
133990075Sobrien    }
134090075Sobrien
134190075Sobrien  if (o->outer)
134290075Sobrien    n->outer = n_array[o->outer->region_number];
134390075Sobrien  if (o->inner)
134490075Sobrien    n->inner = n_array[o->inner->region_number];
134590075Sobrien  if (o->next_peer)
134690075Sobrien    n->next_peer = n_array[o->next_peer->region_number];
134790075Sobrien}
134890075Sobrien
134990075Sobrienint
135090075Sobrienduplicate_eh_regions (ifun, map)
135190075Sobrien     struct function *ifun;
135290075Sobrien     struct inline_remap *map;
135350397Sobrien{
135490075Sobrien  int ifun_last_region_number = ifun->eh->last_region_number;
135590075Sobrien  struct eh_region **n_array, *root, *cur;
135690075Sobrien  int i;
135750397Sobrien
135890075Sobrien  if (ifun_last_region_number == 0)
135990075Sobrien    return 0;
136050397Sobrien
136190075Sobrien  n_array = xcalloc (ifun_last_region_number + 1, sizeof (*n_array));
136250397Sobrien
136390075Sobrien  for (i = 1; i <= ifun_last_region_number; ++i)
136490075Sobrien    {
136590075Sobrien      cur = ifun->eh->region_array[i];
136690075Sobrien      if (!cur || cur->region_number != i)
136790075Sobrien	continue;
136890075Sobrien      n_array[i] = duplicate_eh_region_1 (cur, map);
136990075Sobrien    }
137090075Sobrien  for (i = 1; i <= ifun_last_region_number; ++i)
137190075Sobrien    {
137290075Sobrien      cur = ifun->eh->region_array[i];
137390075Sobrien      if (!cur || cur->region_number != i)
137490075Sobrien	continue;
137590075Sobrien      duplicate_eh_region_2 (cur, n_array);
137690075Sobrien    }
137750397Sobrien
137890075Sobrien  root = n_array[ifun->eh->region_tree->region_number];
137990075Sobrien  cur = cfun->eh->cur_region;
138090075Sobrien  if (cur)
138190075Sobrien    {
138290075Sobrien      struct eh_region *p = cur->inner;
138390075Sobrien      if (p)
138490075Sobrien	{
138590075Sobrien	  while (p->next_peer)
138690075Sobrien	    p = p->next_peer;
138790075Sobrien	  p->next_peer = root;
138890075Sobrien	}
138990075Sobrien      else
139090075Sobrien	cur->inner = root;
139150397Sobrien
139290075Sobrien      for (i = 1; i <= ifun_last_region_number; ++i)
139390075Sobrien	if (n_array[i] && n_array[i]->outer == NULL)
139490075Sobrien	  n_array[i]->outer = cur;
139590075Sobrien    }
139690075Sobrien  else
139790075Sobrien    {
139890075Sobrien      struct eh_region *p = cfun->eh->region_tree;
139990075Sobrien      if (p)
140090075Sobrien	{
140190075Sobrien	  while (p->next_peer)
140290075Sobrien	    p = p->next_peer;
140390075Sobrien	  p->next_peer = root;
140490075Sobrien	}
140590075Sobrien      else
140690075Sobrien	cfun->eh->region_tree = root;
140790075Sobrien    }
140850397Sobrien
140990075Sobrien  free (n_array);
141050397Sobrien
141190075Sobrien  i = cfun->eh->last_region_number;
141290075Sobrien  cfun->eh->last_region_number = i + ifun_last_region_number;
141390075Sobrien  return i;
141490075Sobrien}
141550397Sobrien
141690075Sobrien
141790075Sobrienstatic int
141890075Sobrient2r_eq (pentry, pdata)
141990075Sobrien     const PTR pentry;
142090075Sobrien     const PTR pdata;
142190075Sobrien{
142290075Sobrien  tree entry = (tree) pentry;
142390075Sobrien  tree data = (tree) pdata;
142450397Sobrien
142590075Sobrien  return TREE_PURPOSE (entry) == data;
142690075Sobrien}
142750397Sobrien
142890075Sobrienstatic hashval_t
142990075Sobrient2r_hash (pentry)
143090075Sobrien     const PTR pentry;
143190075Sobrien{
143290075Sobrien  tree entry = (tree) pentry;
143390075Sobrien  return TYPE_HASH (TREE_PURPOSE (entry));
143450397Sobrien}
143550397Sobrien
143650397Sobrienstatic void
143790075Sobrienadd_type_for_runtime (type)
143890075Sobrien     tree type;
143990075Sobrien{
144090075Sobrien  tree *slot;
144150397Sobrien
144290075Sobrien  slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
144390075Sobrien					    TYPE_HASH (type), INSERT);
144490075Sobrien  if (*slot == NULL)
144590075Sobrien    {
144690075Sobrien      tree runtime = (*lang_eh_runtime_type) (type);
144790075Sobrien      *slot = tree_cons (type, runtime, NULL_TREE);
144890075Sobrien    }
144990075Sobrien}
145050397Sobrien
145190075Sobrienstatic tree
145290075Sobrienlookup_type_for_runtime (type)
145390075Sobrien     tree type;
145490075Sobrien{
145590075Sobrien  tree *slot;
145650397Sobrien
145790075Sobrien  slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
145890075Sobrien					    TYPE_HASH (type), NO_INSERT);
145950397Sobrien
146090075Sobrien  /* We should have always inserted the data earlier.  */
146190075Sobrien  return TREE_VALUE (*slot);
146290075Sobrien}
146350397Sobrien
146490075Sobrien
146590075Sobrien/* Represent an entry in @TTypes for either catch actions
146690075Sobrien   or exception filter actions.  */
1467117395Skanstruct ttypes_filter GTY(())
146890075Sobrien{
146990075Sobrien  tree t;
147090075Sobrien  int filter;
147190075Sobrien};
147250397Sobrien
147390075Sobrien/* Compare ENTRY (a ttypes_filter entry in the hash table) with DATA
147490075Sobrien   (a tree) for a @TTypes type node we are thinking about adding.  */
147550397Sobrien
147690075Sobrienstatic int
147790075Sobrienttypes_filter_eq (pentry, pdata)
147890075Sobrien     const PTR pentry;
147990075Sobrien     const PTR pdata;
148090075Sobrien{
148190075Sobrien  const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
148290075Sobrien  tree data = (tree) pdata;
148350397Sobrien
148490075Sobrien  return entry->t == data;
148550397Sobrien}
148650397Sobrien
148790075Sobrienstatic hashval_t
148890075Sobrienttypes_filter_hash (pentry)
148990075Sobrien     const PTR pentry;
149090075Sobrien{
149190075Sobrien  const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
149290075Sobrien  return TYPE_HASH (entry->t);
149390075Sobrien}
149450397Sobrien
149590075Sobrien/* Compare ENTRY with DATA (both struct ttypes_filter) for a @TTypes
149690075Sobrien   exception specification list we are thinking about adding.  */
149790075Sobrien/* ??? Currently we use the type lists in the order given.  Someone
149890075Sobrien   should put these in some canonical order.  */
149950397Sobrien
150090075Sobrienstatic int
150190075Sobrienehspec_filter_eq (pentry, pdata)
150290075Sobrien     const PTR pentry;
150390075Sobrien     const PTR pdata;
150450397Sobrien{
150590075Sobrien  const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
150690075Sobrien  const struct ttypes_filter *data = (const struct ttypes_filter *) pdata;
150750397Sobrien
150890075Sobrien  return type_list_equal (entry->t, data->t);
150990075Sobrien}
151050397Sobrien
151190075Sobrien/* Hash function for exception specification lists.  */
151250397Sobrien
151390075Sobrienstatic hashval_t
151490075Sobrienehspec_filter_hash (pentry)
151590075Sobrien     const PTR pentry;
151690075Sobrien{
151790075Sobrien  const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
151890075Sobrien  hashval_t h = 0;
151990075Sobrien  tree list;
152050397Sobrien
152190075Sobrien  for (list = entry->t; list ; list = TREE_CHAIN (list))
152290075Sobrien    h = (h << 5) + (h >> 27) + TYPE_HASH (TREE_VALUE (list));
152390075Sobrien  return h;
152450397Sobrien}
152550397Sobrien
152690075Sobrien/* Add TYPE to cfun->eh->ttype_data, using TYPES_HASH to speed
152790075Sobrien   up the search.  Return the filter value to be used.  */
152850397Sobrien
152990075Sobrienstatic int
153090075Sobrienadd_ttypes_entry (ttypes_hash, type)
153190075Sobrien     htab_t ttypes_hash;
153290075Sobrien     tree type;
153350397Sobrien{
153490075Sobrien  struct ttypes_filter **slot, *n;
153550397Sobrien
153690075Sobrien  slot = (struct ttypes_filter **)
153790075Sobrien    htab_find_slot_with_hash (ttypes_hash, type, TYPE_HASH (type), INSERT);
153850397Sobrien
153990075Sobrien  if ((n = *slot) == NULL)
154050397Sobrien    {
154190075Sobrien      /* Filter value is a 1 based table index.  */
154250397Sobrien
154390075Sobrien      n = (struct ttypes_filter *) xmalloc (sizeof (*n));
154490075Sobrien      n->t = type;
154590075Sobrien      n->filter = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) + 1;
154690075Sobrien      *slot = n;
154750397Sobrien
154890075Sobrien      VARRAY_PUSH_TREE (cfun->eh->ttype_data, type);
154950397Sobrien    }
155050397Sobrien
155190075Sobrien  return n->filter;
155250397Sobrien}
155350397Sobrien
155490075Sobrien/* Add LIST to cfun->eh->ehspec_data, using EHSPEC_HASH and TYPES_HASH
155590075Sobrien   to speed up the search.  Return the filter value to be used.  */
155650397Sobrien
155790075Sobrienstatic int
155890075Sobrienadd_ehspec_entry (ehspec_hash, ttypes_hash, list)
155990075Sobrien     htab_t ehspec_hash;
156090075Sobrien     htab_t ttypes_hash;
156190075Sobrien     tree list;
156250397Sobrien{
156390075Sobrien  struct ttypes_filter **slot, *n;
156490075Sobrien  struct ttypes_filter dummy;
156550397Sobrien
156690075Sobrien  dummy.t = list;
156790075Sobrien  slot = (struct ttypes_filter **)
156890075Sobrien    htab_find_slot (ehspec_hash, &dummy, INSERT);
156950397Sobrien
157090075Sobrien  if ((n = *slot) == NULL)
157190075Sobrien    {
157290075Sobrien      /* Filter value is a -1 based byte index into a uleb128 buffer.  */
157350397Sobrien
157490075Sobrien      n = (struct ttypes_filter *) xmalloc (sizeof (*n));
157590075Sobrien      n->t = list;
157690075Sobrien      n->filter = -(VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) + 1);
157790075Sobrien      *slot = n;
157850397Sobrien
157990075Sobrien      /* Look up each type in the list and encode its filter
158090075Sobrien	 value as a uleb128.  Terminate the list with 0.  */
158190075Sobrien      for (; list ; list = TREE_CHAIN (list))
158290075Sobrien	push_uleb128 (&cfun->eh->ehspec_data,
158390075Sobrien		      add_ttypes_entry (ttypes_hash, TREE_VALUE (list)));
158490075Sobrien      VARRAY_PUSH_UCHAR (cfun->eh->ehspec_data, 0);
158590075Sobrien    }
158690075Sobrien
158790075Sobrien  return n->filter;
158890075Sobrien}
158990075Sobrien
159090075Sobrien/* Generate the action filter values to be used for CATCH and
159190075Sobrien   ALLOWED_EXCEPTIONS regions.  When using dwarf2 exception regions,
159290075Sobrien   we use lots of landing pads, and so every type or list can share
159390075Sobrien   the same filter value, which saves table space.  */
159490075Sobrien
159590075Sobrienstatic void
159690075Sobrienassign_filter_values ()
159750397Sobrien{
159890075Sobrien  int i;
159990075Sobrien  htab_t ttypes, ehspec;
160050397Sobrien
160190075Sobrien  VARRAY_TREE_INIT (cfun->eh->ttype_data, 16, "ttype_data");
160290075Sobrien  VARRAY_UCHAR_INIT (cfun->eh->ehspec_data, 64, "ehspec_data");
160350397Sobrien
160490075Sobrien  ttypes = htab_create (31, ttypes_filter_hash, ttypes_filter_eq, free);
160590075Sobrien  ehspec = htab_create (31, ehspec_filter_hash, ehspec_filter_eq, free);
160650397Sobrien
160790075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
160850397Sobrien    {
160990075Sobrien      struct eh_region *r = cfun->eh->region_array[i];
161050397Sobrien
161190075Sobrien      /* Mind we don't process a region more than once.  */
161290075Sobrien      if (!r || r->region_number != i)
161390075Sobrien	continue;
161450397Sobrien
161590075Sobrien      switch (r->type)
161690075Sobrien	{
161790075Sobrien	case ERT_CATCH:
161890075Sobrien	  /* Whatever type_list is (NULL or true list), we build a list
161990075Sobrien	     of filters for the region.  */
162090075Sobrien	  r->u.catch.filter_list = NULL_TREE;
162150397Sobrien
162290075Sobrien	  if (r->u.catch.type_list != NULL)
162390075Sobrien	    {
162490075Sobrien	      /* Get a filter value for each of the types caught and store
162590075Sobrien		 them in the region's dedicated list.  */
162690075Sobrien	      tree tp_node = r->u.catch.type_list;
162750397Sobrien
162890075Sobrien	      for (;tp_node; tp_node = TREE_CHAIN (tp_node))
162990075Sobrien		{
163090075Sobrien		  int flt = add_ttypes_entry (ttypes, TREE_VALUE (tp_node));
163190075Sobrien		  tree flt_node = build_int_2 (flt, 0);
163250397Sobrien
163390075Sobrien		  r->u.catch.filter_list
163490075Sobrien		    = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list);
163590075Sobrien		}
163690075Sobrien	    }
163790075Sobrien	  else
163890075Sobrien	    {
163990075Sobrien	      /* Get a filter value for the NULL list also since it will need
164090075Sobrien		 an action record anyway.  */
164190075Sobrien	      int flt = add_ttypes_entry (ttypes, NULL);
164290075Sobrien	      tree flt_node = build_int_2 (flt, 0);
164350397Sobrien
164490075Sobrien	      r->u.catch.filter_list
164590075Sobrien		= tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list);
164690075Sobrien	    }
164750397Sobrien
164890075Sobrien	  break;
164950397Sobrien
165090075Sobrien	case ERT_ALLOWED_EXCEPTIONS:
165190075Sobrien	  r->u.allowed.filter
165290075Sobrien	    = add_ehspec_entry (ehspec, ttypes, r->u.allowed.type_list);
165390075Sobrien	  break;
165450397Sobrien
165590075Sobrien	default:
165690075Sobrien	  break;
165790075Sobrien	}
165850397Sobrien    }
165990075Sobrien
166090075Sobrien  htab_delete (ttypes);
166190075Sobrien  htab_delete (ehspec);
166250397Sobrien}
166350397Sobrien
166490075Sobrienstatic void
166590075Sobrienbuild_post_landing_pads ()
166650397Sobrien{
166790075Sobrien  int i;
166850397Sobrien
166990075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
167090075Sobrien    {
167190075Sobrien      struct eh_region *region = cfun->eh->region_array[i];
167290075Sobrien      rtx seq;
167350397Sobrien
167490075Sobrien      /* Mind we don't process a region more than once.  */
167590075Sobrien      if (!region || region->region_number != i)
167690075Sobrien	continue;
167750397Sobrien
167890075Sobrien      switch (region->type)
167990075Sobrien	{
168090075Sobrien	case ERT_TRY:
168190075Sobrien	  /* ??? Collect the set of all non-overlapping catch handlers
168290075Sobrien	       all the way up the chain until blocked by a cleanup.  */
168390075Sobrien	  /* ??? Outer try regions can share landing pads with inner
168490075Sobrien	     try regions if the types are completely non-overlapping,
168590075Sobrien	     and there are no intervening cleanups.  */
168650397Sobrien
168790075Sobrien	  region->post_landing_pad = gen_label_rtx ();
168850397Sobrien
168990075Sobrien	  start_sequence ();
169050397Sobrien
169190075Sobrien	  emit_label (region->post_landing_pad);
169250397Sobrien
169390075Sobrien	  /* ??? It is mighty inconvenient to call back into the
169490075Sobrien	     switch statement generation code in expand_end_case.
169590075Sobrien	     Rapid prototyping sez a sequence of ifs.  */
169690075Sobrien	  {
169790075Sobrien	    struct eh_region *c;
169890075Sobrien	    for (c = region->u.try.catch; c ; c = c->u.catch.next_catch)
169990075Sobrien	      {
170090075Sobrien		if (c->u.catch.type_list == NULL)
170190075Sobrien		  emit_jump (c->label);
170290075Sobrien		else
170390075Sobrien		  {
170490075Sobrien		    /* Need for one cmp/jump per type caught. Each type
170590075Sobrien		       list entry has a matching entry in the filter list
170690075Sobrien		       (see assign_filter_values).  */
170790075Sobrien		    tree tp_node = c->u.catch.type_list;
170890075Sobrien		    tree flt_node = c->u.catch.filter_list;
170950397Sobrien
171090075Sobrien		    for (; tp_node; )
171190075Sobrien		      {
171290075Sobrien			emit_cmp_and_jump_insns
171390075Sobrien			  (cfun->eh->filter,
171490075Sobrien			   GEN_INT (tree_low_cst (TREE_VALUE (flt_node), 0)),
171590075Sobrien			   EQ, NULL_RTX, word_mode, 0, c->label);
171650397Sobrien
171790075Sobrien			tp_node = TREE_CHAIN (tp_node);
171890075Sobrien			flt_node = TREE_CHAIN (flt_node);
171990075Sobrien		      }
172090075Sobrien		  }
172190075Sobrien	      }
172290075Sobrien	  }
172350397Sobrien
172490075Sobrien	  /* We delay the generation of the _Unwind_Resume until we generate
172590075Sobrien	     landing pads.  We emit a marker here so as to get good control
172690075Sobrien	     flow data in the meantime.  */
172790075Sobrien	  region->resume
172890075Sobrien	    = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
172990075Sobrien	  emit_barrier ();
173050397Sobrien
173190075Sobrien	  seq = get_insns ();
173290075Sobrien	  end_sequence ();
173350397Sobrien
1734117395Skan	  emit_insn_before (seq, region->u.try.catch->label);
173590075Sobrien	  break;
173650397Sobrien
173790075Sobrien	case ERT_ALLOWED_EXCEPTIONS:
173890075Sobrien	  region->post_landing_pad = gen_label_rtx ();
173950397Sobrien
174090075Sobrien	  start_sequence ();
174150397Sobrien
174290075Sobrien	  emit_label (region->post_landing_pad);
174350397Sobrien
174490075Sobrien	  emit_cmp_and_jump_insns (cfun->eh->filter,
174590075Sobrien				   GEN_INT (region->u.allowed.filter),
174690075Sobrien				   EQ, NULL_RTX, word_mode, 0, region->label);
174750397Sobrien
174890075Sobrien	  /* We delay the generation of the _Unwind_Resume until we generate
174990075Sobrien	     landing pads.  We emit a marker here so as to get good control
175090075Sobrien	     flow data in the meantime.  */
175190075Sobrien	  region->resume
175290075Sobrien	    = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
175390075Sobrien	  emit_barrier ();
175450397Sobrien
175590075Sobrien	  seq = get_insns ();
175690075Sobrien	  end_sequence ();
175790075Sobrien
1758117395Skan	  emit_insn_before (seq, region->label);
175990075Sobrien	  break;
176090075Sobrien
176190075Sobrien	case ERT_CLEANUP:
176290075Sobrien	case ERT_MUST_NOT_THROW:
176390075Sobrien	  region->post_landing_pad = region->label;
176490075Sobrien	  break;
176590075Sobrien
176690075Sobrien	case ERT_CATCH:
176790075Sobrien	case ERT_THROW:
176890075Sobrien	  /* Nothing to do.  */
176990075Sobrien	  break;
177090075Sobrien
177190075Sobrien	default:
177290075Sobrien	  abort ();
177390075Sobrien	}
177490075Sobrien    }
177550397Sobrien}
177650397Sobrien
177790075Sobrien/* Replace RESX patterns with jumps to the next handler if any, or calls to
177890075Sobrien   _Unwind_Resume otherwise.  */
177950397Sobrien
178090075Sobrienstatic void
178190075Sobrienconnect_post_landing_pads ()
178250397Sobrien{
178390075Sobrien  int i;
178450397Sobrien
178590075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
178650397Sobrien    {
178790075Sobrien      struct eh_region *region = cfun->eh->region_array[i];
178890075Sobrien      struct eh_region *outer;
178990075Sobrien      rtx seq;
179050397Sobrien
179190075Sobrien      /* Mind we don't process a region more than once.  */
179290075Sobrien      if (!region || region->region_number != i)
179390075Sobrien	continue;
179450397Sobrien
179590075Sobrien      /* If there is no RESX, or it has been deleted by flow, there's
179690075Sobrien	 nothing to fix up.  */
179790075Sobrien      if (! region->resume || INSN_DELETED_P (region->resume))
179890075Sobrien	continue;
179950397Sobrien
180090075Sobrien      /* Search for another landing pad in this function.  */
180190075Sobrien      for (outer = region->outer; outer ; outer = outer->outer)
180290075Sobrien	if (outer->post_landing_pad)
180390075Sobrien	  break;
180450397Sobrien
180590075Sobrien      start_sequence ();
180650397Sobrien
180790075Sobrien      if (outer)
180890075Sobrien	emit_jump (outer->post_landing_pad);
180990075Sobrien      else
181090075Sobrien	emit_library_call (unwind_resume_libfunc, LCT_THROW,
1811117395Skan			   VOIDmode, 1, cfun->eh->exc_ptr, ptr_mode);
181250397Sobrien
181390075Sobrien      seq = get_insns ();
181490075Sobrien      end_sequence ();
1815117395Skan      emit_insn_before (seq, region->resume);
181690075Sobrien      delete_insn (region->resume);
181750397Sobrien    }
181850397Sobrien}
181950397Sobrien
182090075Sobrien
182190075Sobrienstatic void
182290075Sobriendw2_build_landing_pads ()
182350397Sobrien{
182490075Sobrien  int i;
182590075Sobrien  unsigned int j;
182650397Sobrien
182790075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
182890075Sobrien    {
182990075Sobrien      struct eh_region *region = cfun->eh->region_array[i];
183090075Sobrien      rtx seq;
183190075Sobrien      bool clobbers_hard_regs = false;
183250397Sobrien
183390075Sobrien      /* Mind we don't process a region more than once.  */
183490075Sobrien      if (!region || region->region_number != i)
183590075Sobrien	continue;
183650397Sobrien
183790075Sobrien      if (region->type != ERT_CLEANUP
183890075Sobrien	  && region->type != ERT_TRY
183990075Sobrien	  && region->type != ERT_ALLOWED_EXCEPTIONS)
184090075Sobrien	continue;
184150397Sobrien
184290075Sobrien      start_sequence ();
184350397Sobrien
184490075Sobrien      region->landing_pad = gen_label_rtx ();
184590075Sobrien      emit_label (region->landing_pad);
184650397Sobrien
184790075Sobrien#ifdef HAVE_exception_receiver
184890075Sobrien      if (HAVE_exception_receiver)
184990075Sobrien	emit_insn (gen_exception_receiver ());
185090075Sobrien      else
185190075Sobrien#endif
185290075Sobrien#ifdef HAVE_nonlocal_goto_receiver
185390075Sobrien	if (HAVE_nonlocal_goto_receiver)
185490075Sobrien	  emit_insn (gen_nonlocal_goto_receiver ());
185590075Sobrien	else
185690075Sobrien#endif
185790075Sobrien	  { /* Nothing */ }
185850397Sobrien
185990075Sobrien      /* If the eh_return data registers are call-saved, then we
186090075Sobrien	 won't have considered them clobbered from the call that
186190075Sobrien	 threw.  Kill them now.  */
186290075Sobrien      for (j = 0; ; ++j)
186390075Sobrien	{
186490075Sobrien	  unsigned r = EH_RETURN_DATA_REGNO (j);
186590075Sobrien	  if (r == INVALID_REGNUM)
186690075Sobrien	    break;
186790075Sobrien	  if (! call_used_regs[r])
186890075Sobrien	    {
186990075Sobrien	      emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, r)));
187090075Sobrien	      clobbers_hard_regs = true;
187190075Sobrien	    }
187290075Sobrien	}
187352284Sobrien
187490075Sobrien      if (clobbers_hard_regs)
187590075Sobrien	{
187690075Sobrien	  /* @@@ This is a kludge.  Not all machine descriptions define a
187790075Sobrien	     blockage insn, but we must not allow the code we just generated
187890075Sobrien	     to be reordered by scheduling.  So emit an ASM_INPUT to act as
187990075Sobrien	     blockage insn.  */
188090075Sobrien	  emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
188190075Sobrien	}
188252284Sobrien
188390075Sobrien      emit_move_insn (cfun->eh->exc_ptr,
1884117395Skan		      gen_rtx_REG (ptr_mode, EH_RETURN_DATA_REGNO (0)));
188590075Sobrien      emit_move_insn (cfun->eh->filter,
188690075Sobrien		      gen_rtx_REG (word_mode, EH_RETURN_DATA_REGNO (1)));
188752284Sobrien
188890075Sobrien      seq = get_insns ();
188990075Sobrien      end_sequence ();
189052284Sobrien
1891117395Skan      emit_insn_before (seq, region->post_landing_pad);
189252284Sobrien    }
189350397Sobrien}
189450397Sobrien
189590075Sobrien
189690075Sobrienstruct sjlj_lp_info
189790075Sobrien{
189890075Sobrien  int directly_reachable;
189990075Sobrien  int action_index;
190090075Sobrien  int dispatch_index;
190190075Sobrien  int call_site_index;
190290075Sobrien};
190352284Sobrien
190490075Sobrienstatic bool
190590075Sobriensjlj_find_directly_reachable_regions (lp_info)
190690075Sobrien     struct sjlj_lp_info *lp_info;
190752284Sobrien{
190890075Sobrien  rtx insn;
190990075Sobrien  bool found_one = false;
191052284Sobrien
191190075Sobrien  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
191252284Sobrien    {
191390075Sobrien      struct eh_region *region;
191490075Sobrien      enum reachable_code rc;
191590075Sobrien      tree type_thrown;
191690075Sobrien      rtx note;
191790075Sobrien
191890075Sobrien      if (! INSN_P (insn))
191990075Sobrien	continue;
192090075Sobrien
192190075Sobrien      note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
192290075Sobrien      if (!note || INTVAL (XEXP (note, 0)) <= 0)
192390075Sobrien	continue;
192490075Sobrien
192590075Sobrien      region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
192690075Sobrien
192790075Sobrien      type_thrown = NULL_TREE;
192890075Sobrien      if (region->type == ERT_THROW)
192990075Sobrien	{
193090075Sobrien	  type_thrown = region->u.throw.type;
193190075Sobrien	  region = region->outer;
193290075Sobrien	}
193390075Sobrien
193490075Sobrien      /* Find the first containing region that might handle the exception.
193590075Sobrien	 That's the landing pad to which we will transfer control.  */
193690075Sobrien      rc = RNL_NOT_CAUGHT;
193790075Sobrien      for (; region; region = region->outer)
193890075Sobrien	{
193990075Sobrien	  rc = reachable_next_level (region, type_thrown, 0);
194090075Sobrien	  if (rc != RNL_NOT_CAUGHT)
194190075Sobrien	    break;
194290075Sobrien	}
194390075Sobrien      if (rc == RNL_MAYBE_CAUGHT || rc == RNL_CAUGHT)
194490075Sobrien	{
194590075Sobrien	  lp_info[region->region_number].directly_reachable = 1;
194690075Sobrien	  found_one = true;
194790075Sobrien	}
194852284Sobrien    }
194952284Sobrien
195090075Sobrien  return found_one;
195152284Sobrien}
195252284Sobrien
195390075Sobrienstatic void
195490075Sobriensjlj_assign_call_site_values (dispatch_label, lp_info)
195590075Sobrien     rtx dispatch_label;
195690075Sobrien     struct sjlj_lp_info *lp_info;
195790075Sobrien{
195890075Sobrien  htab_t ar_hash;
195990075Sobrien  int i, index;
196050397Sobrien
196190075Sobrien  /* First task: build the action table.  */
196250397Sobrien
196390075Sobrien  VARRAY_UCHAR_INIT (cfun->eh->action_record_data, 64, "action_record_data");
196490075Sobrien  ar_hash = htab_create (31, action_record_hash, action_record_eq, free);
196550397Sobrien
196690075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
196790075Sobrien    if (lp_info[i].directly_reachable)
196890075Sobrien      {
196990075Sobrien	struct eh_region *r = cfun->eh->region_array[i];
197090075Sobrien	r->landing_pad = dispatch_label;
197190075Sobrien	lp_info[i].action_index = collect_one_action_chain (ar_hash, r);
197290075Sobrien	if (lp_info[i].action_index != -1)
197390075Sobrien	  cfun->uses_eh_lsda = 1;
197490075Sobrien      }
197550397Sobrien
197690075Sobrien  htab_delete (ar_hash);
197750397Sobrien
197890075Sobrien  /* Next: assign dispatch values.  In dwarf2 terms, this would be the
197990075Sobrien     landing pad label for the region.  For sjlj though, there is one
198090075Sobrien     common landing pad from which we dispatch to the post-landing pads.
198150397Sobrien
198290075Sobrien     A region receives a dispatch index if it is directly reachable
198390075Sobrien     and requires in-function processing.  Regions that share post-landing
198490075Sobrien     pads may share dispatch indices.  */
198590075Sobrien  /* ??? Post-landing pad sharing doesn't actually happen at the moment
198690075Sobrien     (see build_post_landing_pads) so we don't bother checking for it.  */
198750397Sobrien
198890075Sobrien  index = 0;
198990075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
199090075Sobrien    if (lp_info[i].directly_reachable)
199190075Sobrien      lp_info[i].dispatch_index = index++;
199250397Sobrien
199390075Sobrien  /* Finally: assign call-site values.  If dwarf2 terms, this would be
199490075Sobrien     the region number assigned by convert_to_eh_region_ranges, but
199590075Sobrien     handles no-action and must-not-throw differently.  */
199650397Sobrien
199790075Sobrien  call_site_base = 1;
199890075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
199990075Sobrien    if (lp_info[i].directly_reachable)
200090075Sobrien      {
200190075Sobrien	int action = lp_info[i].action_index;
200290075Sobrien
200390075Sobrien	/* Map must-not-throw to otherwise unused call-site index 0.  */
200490075Sobrien	if (action == -2)
200590075Sobrien	  index = 0;
200690075Sobrien	/* Map no-action to otherwise unused call-site index -1.  */
200790075Sobrien	else if (action == -1)
200890075Sobrien	  index = -1;
200990075Sobrien	/* Otherwise, look it up in the table.  */
201090075Sobrien	else
201190075Sobrien	  index = add_call_site (GEN_INT (lp_info[i].dispatch_index), action);
201290075Sobrien
201390075Sobrien	lp_info[i].call_site_index = index;
201490075Sobrien      }
201590075Sobrien}
201690075Sobrien
201790075Sobrienstatic void
201890075Sobriensjlj_mark_call_sites (lp_info)
201990075Sobrien     struct sjlj_lp_info *lp_info;
202090075Sobrien{
202190075Sobrien  int last_call_site = -2;
202290075Sobrien  rtx insn, mem;
202390075Sobrien
202490075Sobrien  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
202550397Sobrien    {
202690075Sobrien      struct eh_region *region;
202790075Sobrien      int this_call_site;
202890075Sobrien      rtx note, before, p;
202950397Sobrien
203090075Sobrien      /* Reset value tracking at extended basic block boundaries.  */
203190075Sobrien      if (GET_CODE (insn) == CODE_LABEL)
203290075Sobrien	last_call_site = -2;
203350397Sobrien
203490075Sobrien      if (! INSN_P (insn))
203590075Sobrien	continue;
203650397Sobrien
203790075Sobrien      note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
203890075Sobrien      if (!note)
203990075Sobrien	{
204090075Sobrien	  /* Calls (and trapping insns) without notes are outside any
204190075Sobrien	     exception handling region in this function.  Mark them as
204290075Sobrien	     no action.  */
204390075Sobrien	  if (GET_CODE (insn) == CALL_INSN
204490075Sobrien	      || (flag_non_call_exceptions
204590075Sobrien		  && may_trap_p (PATTERN (insn))))
204690075Sobrien	    this_call_site = -1;
204790075Sobrien	  else
204890075Sobrien	    continue;
204990075Sobrien	}
205090075Sobrien      else
205190075Sobrien	{
205290075Sobrien	  /* Calls that are known to not throw need not be marked.  */
205390075Sobrien	  if (INTVAL (XEXP (note, 0)) <= 0)
205490075Sobrien	    continue;
205550397Sobrien
205690075Sobrien	  region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
205790075Sobrien	  this_call_site = lp_info[region->region_number].call_site_index;
205890075Sobrien	}
205950397Sobrien
206090075Sobrien      if (this_call_site == last_call_site)
206190075Sobrien	continue;
206250397Sobrien
206390075Sobrien      /* Don't separate a call from it's argument loads.  */
206490075Sobrien      before = insn;
206590075Sobrien      if (GET_CODE (insn) == CALL_INSN)
2066117395Skan	before = find_first_parameter_load (insn, NULL_RTX);
206750397Sobrien
206890075Sobrien      start_sequence ();
206990075Sobrien      mem = adjust_address (cfun->eh->sjlj_fc, TYPE_MODE (integer_type_node),
207090075Sobrien			    sjlj_fc_call_site_ofs);
207190075Sobrien      emit_move_insn (mem, GEN_INT (this_call_site));
207290075Sobrien      p = get_insns ();
207390075Sobrien      end_sequence ();
207450397Sobrien
2075117395Skan      emit_insn_before (p, before);
207690075Sobrien      last_call_site = this_call_site;
207750397Sobrien    }
207850397Sobrien}
207950397Sobrien
208090075Sobrien/* Construct the SjLj_Function_Context.  */
208150397Sobrien
208290075Sobrienstatic void
208390075Sobriensjlj_emit_function_enter (dispatch_label)
208490075Sobrien     rtx dispatch_label;
208550397Sobrien{
208690075Sobrien  rtx fn_begin, fc, mem, seq;
208750397Sobrien
208890075Sobrien  fc = cfun->eh->sjlj_fc;
208950397Sobrien
209090075Sobrien  start_sequence ();
209150397Sobrien
209290075Sobrien  /* We're storing this libcall's address into memory instead of
209390075Sobrien     calling it directly.  Thus, we must call assemble_external_libcall
209490075Sobrien     here, as we can not depend on emit_library_call to do it for us.  */
209590075Sobrien  assemble_external_libcall (eh_personality_libfunc);
209690075Sobrien  mem = adjust_address (fc, Pmode, sjlj_fc_personality_ofs);
209790075Sobrien  emit_move_insn (mem, eh_personality_libfunc);
209890075Sobrien
209990075Sobrien  mem = adjust_address (fc, Pmode, sjlj_fc_lsda_ofs);
210090075Sobrien  if (cfun->uses_eh_lsda)
210150397Sobrien    {
210290075Sobrien      char buf[20];
2103117395Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LLSDA", current_function_funcdef_no);
210490075Sobrien      emit_move_insn (mem, gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)));
210550397Sobrien    }
210690075Sobrien  else
210790075Sobrien    emit_move_insn (mem, const0_rtx);
210850397Sobrien
210990075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP
211090075Sobrien  {
211190075Sobrien    rtx x, note;
211290075Sobrien    x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_RETURNS_TWICE,
211390075Sobrien				 TYPE_MODE (integer_type_node), 1,
211490075Sobrien				 plus_constant (XEXP (fc, 0),
211590075Sobrien						sjlj_fc_jbuf_ofs), Pmode);
211650397Sobrien
211790075Sobrien    note = emit_note (NULL, NOTE_INSN_EXPECTED_VALUE);
211890075Sobrien    NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, x, const0_rtx);
211950397Sobrien
212090075Sobrien    emit_cmp_and_jump_insns (x, const0_rtx, NE, 0,
212190075Sobrien			     TYPE_MODE (integer_type_node), 0, dispatch_label);
212290075Sobrien  }
212390075Sobrien#else
212490075Sobrien  expand_builtin_setjmp_setup (plus_constant (XEXP (fc, 0), sjlj_fc_jbuf_ofs),
212590075Sobrien			       dispatch_label);
212690075Sobrien#endif
212750397Sobrien
212890075Sobrien  emit_library_call (unwind_sjlj_register_libfunc, LCT_NORMAL, VOIDmode,
212990075Sobrien		     1, XEXP (fc, 0), Pmode);
213090075Sobrien
213190075Sobrien  seq = get_insns ();
213250397Sobrien  end_sequence ();
213350397Sobrien
213490075Sobrien  /* ??? Instead of doing this at the beginning of the function,
213590075Sobrien     do this in a block that is at loop level 0 and dominates all
213690075Sobrien     can_throw_internal instructions.  */
213750397Sobrien
213890075Sobrien  for (fn_begin = get_insns (); ; fn_begin = NEXT_INSN (fn_begin))
213990075Sobrien    if (GET_CODE (fn_begin) == NOTE
214090075Sobrien	&& NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG)
214190075Sobrien      break;
2142117395Skan  emit_insn_after (seq, fn_begin);
214350397Sobrien}
214450397Sobrien
214590075Sobrien/* Call back from expand_function_end to know where we should put
214690075Sobrien   the call to unwind_sjlj_unregister_libfunc if needed.  */
214750397Sobrien
214850397Sobrienvoid
214990075Sobriensjlj_emit_function_exit_after (after)
215090075Sobrien     rtx after;
215150397Sobrien{
215290075Sobrien  cfun->eh->sjlj_exit_after = after;
215350397Sobrien}
215450397Sobrien
215590075Sobrienstatic void
215690075Sobriensjlj_emit_function_exit ()
215750397Sobrien{
215890075Sobrien  rtx seq;
215950397Sobrien
216090075Sobrien  start_sequence ();
216150397Sobrien
216290075Sobrien  emit_library_call (unwind_sjlj_unregister_libfunc, LCT_NORMAL, VOIDmode,
216390075Sobrien		     1, XEXP (cfun->eh->sjlj_fc, 0), Pmode);
216450397Sobrien
216590075Sobrien  seq = get_insns ();
216690075Sobrien  end_sequence ();
216750397Sobrien
216890075Sobrien  /* ??? Really this can be done in any block at loop level 0 that
216990075Sobrien     post-dominates all can_throw_internal instructions.  This is
217090075Sobrien     the last possible moment.  */
217150397Sobrien
2172117395Skan  emit_insn_after (seq, cfun->eh->sjlj_exit_after);
217390075Sobrien}
217450397Sobrien
217590075Sobrienstatic void
217690075Sobriensjlj_emit_dispatch_table (dispatch_label, lp_info)
217790075Sobrien     rtx dispatch_label;
217890075Sobrien     struct sjlj_lp_info *lp_info;
217990075Sobrien{
218090075Sobrien  int i, first_reachable;
218190075Sobrien  rtx mem, dispatch, seq, fc;
218250397Sobrien
218390075Sobrien  fc = cfun->eh->sjlj_fc;
218450397Sobrien
218590075Sobrien  start_sequence ();
218650397Sobrien
218790075Sobrien  emit_label (dispatch_label);
218850397Sobrien
218990075Sobrien#ifndef DONT_USE_BUILTIN_SETJMP
219090075Sobrien  expand_builtin_setjmp_receiver (dispatch_label);
219190075Sobrien#endif
219250397Sobrien
219390075Sobrien  /* Load up dispatch index, exc_ptr and filter values from the
219490075Sobrien     function context.  */
219590075Sobrien  mem = adjust_address (fc, TYPE_MODE (integer_type_node),
219690075Sobrien			sjlj_fc_call_site_ofs);
219790075Sobrien  dispatch = copy_to_reg (mem);
219850397Sobrien
219990075Sobrien  mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs);
220090075Sobrien  if (word_mode != Pmode)
220150397Sobrien    {
220290075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED
220390075Sobrien      mem = convert_memory_address (Pmode, mem);
220490075Sobrien#else
220590075Sobrien      mem = convert_to_mode (Pmode, mem, 0);
220690075Sobrien#endif
220790075Sobrien    }
220890075Sobrien  emit_move_insn (cfun->eh->exc_ptr, mem);
220950397Sobrien
221090075Sobrien  mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs + UNITS_PER_WORD);
221190075Sobrien  emit_move_insn (cfun->eh->filter, mem);
221250397Sobrien
221390075Sobrien  /* Jump to one of the directly reachable regions.  */
221490075Sobrien  /* ??? This really ought to be using a switch statement.  */
221590075Sobrien
221690075Sobrien  first_reachable = 0;
221790075Sobrien  for (i = cfun->eh->last_region_number; i > 0; --i)
221890075Sobrien    {
221990075Sobrien      if (! lp_info[i].directly_reachable)
222090075Sobrien	continue;
222190075Sobrien
222290075Sobrien      if (! first_reachable)
222350397Sobrien	{
222490075Sobrien	  first_reachable = i;
222590075Sobrien	  continue;
222650397Sobrien	}
222790075Sobrien
222890075Sobrien      emit_cmp_and_jump_insns (dispatch, GEN_INT (lp_info[i].dispatch_index),
222990075Sobrien			       EQ, NULL_RTX, TYPE_MODE (integer_type_node), 0,
223090075Sobrien			       cfun->eh->region_array[i]->post_landing_pad);
223150397Sobrien    }
223250397Sobrien
223390075Sobrien  seq = get_insns ();
223490075Sobrien  end_sequence ();
223550397Sobrien
2236117395Skan  emit_insn_before (seq, (cfun->eh->region_array[first_reachable]
2237117395Skan			  ->post_landing_pad));
223850397Sobrien}
223950397Sobrien
224050397Sobrienstatic void
224190075Sobriensjlj_build_landing_pads ()
224250397Sobrien{
224390075Sobrien  struct sjlj_lp_info *lp_info;
224450397Sobrien
224590075Sobrien  lp_info = (struct sjlj_lp_info *) xcalloc (cfun->eh->last_region_number + 1,
224690075Sobrien					     sizeof (struct sjlj_lp_info));
224750397Sobrien
224890075Sobrien  if (sjlj_find_directly_reachable_regions (lp_info))
224950397Sobrien    {
225090075Sobrien      rtx dispatch_label = gen_label_rtx ();
225152284Sobrien
225290075Sobrien      cfun->eh->sjlj_fc
225390075Sobrien	= assign_stack_local (TYPE_MODE (sjlj_fc_type_node),
225490075Sobrien			      int_size_in_bytes (sjlj_fc_type_node),
225590075Sobrien			      TYPE_ALIGN (sjlj_fc_type_node));
225650397Sobrien
225790075Sobrien      sjlj_assign_call_site_values (dispatch_label, lp_info);
225890075Sobrien      sjlj_mark_call_sites (lp_info);
225950397Sobrien
226090075Sobrien      sjlj_emit_function_enter (dispatch_label);
226190075Sobrien      sjlj_emit_dispatch_table (dispatch_label, lp_info);
226290075Sobrien      sjlj_emit_function_exit ();
226350397Sobrien    }
226450397Sobrien
226590075Sobrien  free (lp_info);
226650397Sobrien}
226750397Sobrien
226852284Sobrienvoid
226990075Sobrienfinish_eh_generation ()
227050397Sobrien{
227190075Sobrien  /* Nothing to do if no regions created.  */
227290075Sobrien  if (cfun->eh->region_tree == NULL)
227390075Sobrien    return;
227450397Sobrien
227590075Sobrien  /* The object here is to provide find_basic_blocks with detailed
227690075Sobrien     information (via reachable_handlers) on how exception control
227790075Sobrien     flows within the function.  In this first pass, we can include
227890075Sobrien     type information garnered from ERT_THROW and ERT_ALLOWED_EXCEPTIONS
227990075Sobrien     regions, and hope that it will be useful in deleting unreachable
228090075Sobrien     handlers.  Subsequently, we will generate landing pads which will
228190075Sobrien     connect many of the handlers, and then type information will not
228290075Sobrien     be effective.  Still, this is a win over previous implementations.  */
228350397Sobrien
2284117395Skan  cleanup_cfg (CLEANUP_PRE_LOOP | CLEANUP_NO_INSN_DEL);
228550397Sobrien
228690075Sobrien  /* These registers are used by the landing pads.  Make sure they
228790075Sobrien     have been generated.  */
228890075Sobrien  get_exception_pointer (cfun);
228990075Sobrien  get_exception_filter (cfun);
229050397Sobrien
229190075Sobrien  /* Construct the landing pads.  */
229250397Sobrien
229390075Sobrien  assign_filter_values ();
229490075Sobrien  build_post_landing_pads ();
229590075Sobrien  connect_post_landing_pads ();
229690075Sobrien  if (USING_SJLJ_EXCEPTIONS)
229790075Sobrien    sjlj_build_landing_pads ();
229890075Sobrien  else
229990075Sobrien    dw2_build_landing_pads ();
230050397Sobrien
230190075Sobrien  cfun->eh->built_landing_pads = 1;
230250397Sobrien
230390075Sobrien  /* We've totally changed the CFG.  Start over.  */
230490075Sobrien  find_exception_handler_labels ();
230590075Sobrien  rebuild_jump_labels (get_insns ());
230690075Sobrien  find_basic_blocks (get_insns (), max_reg_num (), 0);
2307117395Skan  cleanup_cfg (CLEANUP_PRE_LOOP | CLEANUP_NO_INSN_DEL);
230890075Sobrien}
230990075Sobrien
231096263Sobrienstatic hashval_t
231196263Sobrienehl_hash (pentry)
231296263Sobrien     const PTR pentry;
231396263Sobrien{
231496263Sobrien  struct ehl_map_entry *entry = (struct ehl_map_entry *) pentry;
231596263Sobrien
231696263Sobrien  /* 2^32 * ((sqrt(5) - 1) / 2) */
231796263Sobrien  const hashval_t scaled_golden_ratio = 0x9e3779b9;
231896263Sobrien  return CODE_LABEL_NUMBER (entry->label) * scaled_golden_ratio;
231996263Sobrien}
232096263Sobrien
232196263Sobrienstatic int
232296263Sobrienehl_eq (pentry, pdata)
232396263Sobrien     const PTR pentry;
232496263Sobrien     const PTR pdata;
232596263Sobrien{
232696263Sobrien  struct ehl_map_entry *entry = (struct ehl_map_entry *) pentry;
232796263Sobrien  struct ehl_map_entry *data = (struct ehl_map_entry *) pdata;
232896263Sobrien
232996263Sobrien  return entry->label == data->label;
233096263Sobrien}
233196263Sobrien
233290075Sobrien/* This section handles removing dead code for flow.  */
233352284Sobrien
233496263Sobrien/* Remove LABEL from exception_handler_label_map.  */
233550397Sobrien
233690075Sobrienstatic void
233790075Sobrienremove_exception_handler_label (label)
233890075Sobrien     rtx label;
233990075Sobrien{
234096263Sobrien  struct ehl_map_entry **slot, tmp;
234150397Sobrien
234296263Sobrien  /* If exception_handler_label_map was not built yet,
234390075Sobrien     there is nothing to do.  */
2344117395Skan  if (cfun->eh->exception_handler_label_map == NULL)
234590075Sobrien    return;
234650397Sobrien
234796263Sobrien  tmp.label = label;
234896263Sobrien  slot = (struct ehl_map_entry **)
2349117395Skan    htab_find_slot (cfun->eh->exception_handler_label_map, &tmp, NO_INSERT);
235096263Sobrien  if (! slot)
235196263Sobrien    abort ();
235250397Sobrien
2353117395Skan  htab_clear_slot (cfun->eh->exception_handler_label_map, (void **) slot);
235450397Sobrien}
235550397Sobrien
235690075Sobrien/* Splice REGION from the region tree etc.  */
235750397Sobrien
235890075Sobrienstatic void
235990075Sobrienremove_eh_handler (region)
236090075Sobrien     struct eh_region *region;
236150397Sobrien{
236296263Sobrien  struct eh_region **pp, **pp_start, *p, *outer, *inner;
236390075Sobrien  rtx lab;
236450397Sobrien
236590075Sobrien  /* For the benefit of efficiently handling REG_EH_REGION notes,
236690075Sobrien     replace this region in the region array with its containing
236790075Sobrien     region.  Note that previous region deletions may result in
236896263Sobrien     multiple copies of this region in the array, so we have a
236996263Sobrien     list of alternate numbers by which we are known.  */
237050397Sobrien
237196263Sobrien  outer = region->outer;
237296263Sobrien  cfun->eh->region_array[region->region_number] = outer;
237396263Sobrien  if (region->aka)
237496263Sobrien    {
237596263Sobrien      int i;
237696263Sobrien      EXECUTE_IF_SET_IN_BITMAP (region->aka, 0, i,
237796263Sobrien	{ cfun->eh->region_array[i] = outer; });
237896263Sobrien    }
237996263Sobrien
238096263Sobrien  if (outer)
238196263Sobrien    {
238296263Sobrien      if (!outer->aka)
2383117395Skan        outer->aka = BITMAP_GGC_ALLOC ();
238496263Sobrien      if (region->aka)
238596263Sobrien	bitmap_a_or_b (outer->aka, outer->aka, region->aka);
238696263Sobrien      bitmap_set_bit (outer->aka, region->region_number);
238796263Sobrien    }
238896263Sobrien
238990075Sobrien  if (cfun->eh->built_landing_pads)
239090075Sobrien    lab = region->landing_pad;
239190075Sobrien  else
239290075Sobrien    lab = region->label;
239390075Sobrien  if (lab)
239490075Sobrien    remove_exception_handler_label (lab);
239550397Sobrien
239696263Sobrien  if (outer)
239796263Sobrien    pp_start = &outer->inner;
239890075Sobrien  else
239996263Sobrien    pp_start = &cfun->eh->region_tree;
240096263Sobrien  for (pp = pp_start, p = *pp; p != region; pp = &p->next_peer, p = *pp)
240190075Sobrien    continue;
240296263Sobrien  *pp = region->next_peer;
240350397Sobrien
240496263Sobrien  inner = region->inner;
240596263Sobrien  if (inner)
240690075Sobrien    {
240796263Sobrien      for (p = inner; p->next_peer ; p = p->next_peer)
240896263Sobrien	p->outer = outer;
240996263Sobrien      p->outer = outer;
241096263Sobrien
241196263Sobrien      p->next_peer = *pp_start;
241296263Sobrien      *pp_start = inner;
241390075Sobrien    }
241450397Sobrien
241590075Sobrien  if (region->type == ERT_CATCH)
241690075Sobrien    {
241790075Sobrien      struct eh_region *try, *next, *prev;
241852284Sobrien
241990075Sobrien      for (try = region->next_peer;
242090075Sobrien	   try->type == ERT_CATCH;
242190075Sobrien	   try = try->next_peer)
242290075Sobrien	continue;
242390075Sobrien      if (try->type != ERT_TRY)
242490075Sobrien	abort ();
242590075Sobrien
242690075Sobrien      next = region->u.catch.next_catch;
242790075Sobrien      prev = region->u.catch.prev_catch;
242890075Sobrien
242990075Sobrien      if (next)
243090075Sobrien	next->u.catch.prev_catch = prev;
243190075Sobrien      else
243290075Sobrien	try->u.try.last_catch = prev;
243390075Sobrien      if (prev)
243490075Sobrien	prev->u.catch.next_catch = next;
243590075Sobrien      else
243690075Sobrien	{
243790075Sobrien	  try->u.try.catch = next;
243890075Sobrien	  if (! next)
243990075Sobrien	    remove_eh_handler (try);
244090075Sobrien	}
244190075Sobrien    }
244250397Sobrien}
244350397Sobrien
244490075Sobrien/* LABEL heads a basic block that is about to be deleted.  If this
244590075Sobrien   label corresponds to an exception region, we may be able to
244690075Sobrien   delete the region.  */
244750397Sobrien
244850397Sobrienvoid
244990075Sobrienmaybe_remove_eh_handler (label)
245090075Sobrien     rtx label;
245150397Sobrien{
245296263Sobrien  struct ehl_map_entry **slot, tmp;
245396263Sobrien  struct eh_region *region;
245450397Sobrien
245590075Sobrien  /* ??? After generating landing pads, it's not so simple to determine
245690075Sobrien     if the region data is completely unused.  One must examine the
245790075Sobrien     landing pad and the post landing pad, and whether an inner try block
245890075Sobrien     is referencing the catch handlers directly.  */
245990075Sobrien  if (cfun->eh->built_landing_pads)
246050397Sobrien    return;
246150397Sobrien
246296263Sobrien  tmp.label = label;
246396263Sobrien  slot = (struct ehl_map_entry **)
2464117395Skan    htab_find_slot (cfun->eh->exception_handler_label_map, &tmp, NO_INSERT);
246596263Sobrien  if (! slot)
246696263Sobrien    return;
246796263Sobrien  region = (*slot)->region;
246896263Sobrien  if (! region)
246996263Sobrien    return;
247096263Sobrien
247196263Sobrien  /* Flow will want to remove MUST_NOT_THROW regions as unreachable
247296263Sobrien     because there is no path to the fallback call to terminate.
247396263Sobrien     But the region continues to affect call-site data until there
247496263Sobrien     are no more contained calls, which we don't see here.  */
247596263Sobrien  if (region->type == ERT_MUST_NOT_THROW)
247650397Sobrien    {
2477117395Skan      htab_clear_slot (cfun->eh->exception_handler_label_map, (void **) slot);
247896263Sobrien      region->label = NULL_RTX;
247950397Sobrien    }
248096263Sobrien  else
248196263Sobrien    remove_eh_handler (region);
248250397Sobrien}
248350397Sobrien
248496263Sobrien/* Invokes CALLBACK for every exception handler label.  Only used by old
248596263Sobrien   loop hackery; should not be used by new code.  */
248696263Sobrien
248796263Sobrienvoid
248896263Sobrienfor_each_eh_label (callback)
248996263Sobrien     void (*callback) PARAMS ((rtx));
249096263Sobrien{
2491117395Skan  htab_traverse (cfun->eh->exception_handler_label_map, for_each_eh_label_1,
249296263Sobrien		 (void *)callback);
249396263Sobrien}
249496263Sobrien
249596263Sobrienstatic int
249696263Sobrienfor_each_eh_label_1 (pentry, data)
249796263Sobrien     PTR *pentry;
249896263Sobrien     PTR data;
249996263Sobrien{
250096263Sobrien  struct ehl_map_entry *entry = *(struct ehl_map_entry **)pentry;
250196263Sobrien  void (*callback) PARAMS ((rtx)) = (void (*) PARAMS ((rtx))) data;
250296263Sobrien
250396263Sobrien  (*callback) (entry->label);
250496263Sobrien  return 1;
250596263Sobrien}
250690075Sobrien
250790075Sobrien/* This section describes CFG exception edges for flow.  */
250850397Sobrien
250990075Sobrien/* For communicating between calls to reachable_next_level.  */
2510117395Skanstruct reachable_info GTY(())
251150397Sobrien{
251290075Sobrien  tree types_caught;
251390075Sobrien  tree types_allowed;
251490075Sobrien  rtx handlers;
251590075Sobrien};
251690075Sobrien
251790075Sobrien/* A subroutine of reachable_next_level.  Return true if TYPE, or a
251890075Sobrien   base class of TYPE, is in HANDLED.  */
251990075Sobrien
252090075Sobrienstatic int
252190075Sobriencheck_handled (handled, type)
252290075Sobrien     tree handled, type;
252390075Sobrien{
252490075Sobrien  tree t;
252590075Sobrien
252690075Sobrien  /* We can check for exact matches without front-end help.  */
252790075Sobrien  if (! lang_eh_type_covers)
252890075Sobrien    {
252990075Sobrien      for (t = handled; t ; t = TREE_CHAIN (t))
253090075Sobrien	if (TREE_VALUE (t) == type)
253190075Sobrien	  return 1;
253290075Sobrien    }
253390075Sobrien  else
253490075Sobrien    {
253590075Sobrien      for (t = handled; t ; t = TREE_CHAIN (t))
253690075Sobrien	if ((*lang_eh_type_covers) (TREE_VALUE (t), type))
253790075Sobrien	  return 1;
253890075Sobrien    }
253990075Sobrien
254050397Sobrien  return 0;
254150397Sobrien}
254250397Sobrien
254390075Sobrien/* A subroutine of reachable_next_level.  If we are collecting a list
254490075Sobrien   of handlers, add one.  After landing pad generation, reference
254590075Sobrien   it instead of the handlers themselves.  Further, the handlers are
254690075Sobrien   all wired together, so by referencing one, we've got them all.
254790075Sobrien   Before landing pad generation we reference each handler individually.
254850397Sobrien
254990075Sobrien   LP_REGION contains the landing pad; REGION is the handler.  */
255050397Sobrien
255190075Sobrienstatic void
255290075Sobrienadd_reachable_handler (info, lp_region, region)
255390075Sobrien     struct reachable_info *info;
255490075Sobrien     struct eh_region *lp_region;
255590075Sobrien     struct eh_region *region;
255650397Sobrien{
255790075Sobrien  if (! info)
255850397Sobrien    return;
255950397Sobrien
256090075Sobrien  if (cfun->eh->built_landing_pads)
256150397Sobrien    {
256290075Sobrien      if (! info->handlers)
256390075Sobrien	info->handlers = alloc_INSN_LIST (lp_region->landing_pad, NULL_RTX);
256450397Sobrien    }
256590075Sobrien  else
256690075Sobrien    info->handlers = alloc_INSN_LIST (region->label, info->handlers);
256750397Sobrien}
256850397Sobrien
256990075Sobrien/* Process one level of exception regions for reachability.
257090075Sobrien   If TYPE_THROWN is non-null, then it is the *exact* type being
257190075Sobrien   propagated.  If INFO is non-null, then collect handler labels
257290075Sobrien   and caught/allowed type information between invocations.  */
257350397Sobrien
257490075Sobrienstatic enum reachable_code
257590075Sobrienreachable_next_level (region, type_thrown, info)
257690075Sobrien     struct eh_region *region;
257790075Sobrien     tree type_thrown;
257890075Sobrien     struct reachable_info *info;
257950397Sobrien{
258090075Sobrien  switch (region->type)
258190075Sobrien    {
258290075Sobrien    case ERT_CLEANUP:
258390075Sobrien      /* Before landing-pad generation, we model control flow
258490075Sobrien	 directly to the individual handlers.  In this way we can
258590075Sobrien	 see that catch handler types may shadow one another.  */
258690075Sobrien      add_reachable_handler (info, region, region);
258790075Sobrien      return RNL_MAYBE_CAUGHT;
258850397Sobrien
258990075Sobrien    case ERT_TRY:
259090075Sobrien      {
259190075Sobrien	struct eh_region *c;
259290075Sobrien	enum reachable_code ret = RNL_NOT_CAUGHT;
259350397Sobrien
259490075Sobrien	for (c = region->u.try.catch; c ; c = c->u.catch.next_catch)
259590075Sobrien	  {
259690075Sobrien	    /* A catch-all handler ends the search.  */
259790075Sobrien	    if (c->u.catch.type_list == NULL)
259890075Sobrien	      {
259990075Sobrien		add_reachable_handler (info, region, c);
260090075Sobrien		return RNL_CAUGHT;
260190075Sobrien	      }
260250397Sobrien
260390075Sobrien	    if (type_thrown)
260490075Sobrien	      {
260590075Sobrien		/* If we have at least one type match, end the search.  */
260690075Sobrien		tree tp_node = c->u.catch.type_list;
260750397Sobrien
260890075Sobrien		for (; tp_node; tp_node = TREE_CHAIN (tp_node))
260990075Sobrien		  {
261090075Sobrien		    tree type = TREE_VALUE (tp_node);
261150397Sobrien
261290075Sobrien		    if (type == type_thrown
261390075Sobrien			|| (lang_eh_type_covers
261490075Sobrien			    && (*lang_eh_type_covers) (type, type_thrown)))
261590075Sobrien		      {
261690075Sobrien			add_reachable_handler (info, region, c);
261790075Sobrien			return RNL_CAUGHT;
261890075Sobrien		      }
261990075Sobrien		  }
262050397Sobrien
262190075Sobrien		/* If we have definitive information of a match failure,
262290075Sobrien		   the catch won't trigger.  */
262390075Sobrien		if (lang_eh_type_covers)
262490075Sobrien		  return RNL_NOT_CAUGHT;
262590075Sobrien	      }
262650397Sobrien
262790075Sobrien	    /* At this point, we either don't know what type is thrown or
262890075Sobrien	       don't have front-end assistance to help deciding if it is
262990075Sobrien	       covered by one of the types in the list for this region.
263050397Sobrien
263190075Sobrien	       We'd then like to add this region to the list of reachable
263290075Sobrien	       handlers since it is indeed potentially reachable based on the
263390075Sobrien	       information we have.
263450397Sobrien
263590075Sobrien	       Actually, this handler is for sure not reachable if all the
263690075Sobrien	       types it matches have already been caught. That is, it is only
263790075Sobrien	       potentially reachable if at least one of the types it catches
263890075Sobrien	       has not been previously caught.  */
263950397Sobrien
264090075Sobrien	    if (! info)
264190075Sobrien	      ret = RNL_MAYBE_CAUGHT;
264290075Sobrien	    else
264390075Sobrien	      {
264490075Sobrien		tree tp_node = c->u.catch.type_list;
264590075Sobrien		bool maybe_reachable = false;
264650397Sobrien
264790075Sobrien		/* Compute the potential reachability of this handler and
264890075Sobrien		   update the list of types caught at the same time.  */
264990075Sobrien		for (; tp_node; tp_node = TREE_CHAIN (tp_node))
265090075Sobrien		  {
265190075Sobrien		    tree type = TREE_VALUE (tp_node);
265290075Sobrien
265390075Sobrien		    if (! check_handled (info->types_caught, type))
265490075Sobrien		      {
265590075Sobrien			info->types_caught
265690075Sobrien			  = tree_cons (NULL, type, info->types_caught);
265790075Sobrien
265890075Sobrien			maybe_reachable = true;
265990075Sobrien		      }
266090075Sobrien		  }
266190075Sobrien
266290075Sobrien		if (maybe_reachable)
266390075Sobrien		  {
266490075Sobrien		    add_reachable_handler (info, region, c);
266590075Sobrien
266690075Sobrien		    /* ??? If the catch type is a base class of every allowed
266790075Sobrien		       type, then we know we can stop the search.  */
266890075Sobrien		    ret = RNL_MAYBE_CAUGHT;
266990075Sobrien		  }
267090075Sobrien	      }
267190075Sobrien	  }
267290075Sobrien
267390075Sobrien	return ret;
267490075Sobrien      }
267590075Sobrien
267690075Sobrien    case ERT_ALLOWED_EXCEPTIONS:
267790075Sobrien      /* An empty list of types definitely ends the search.  */
267890075Sobrien      if (region->u.allowed.type_list == NULL_TREE)
267990075Sobrien	{
268090075Sobrien	  add_reachable_handler (info, region, region);
268190075Sobrien	  return RNL_CAUGHT;
268290075Sobrien	}
268390075Sobrien
268490075Sobrien      /* Collect a list of lists of allowed types for use in detecting
268590075Sobrien	 when a catch may be transformed into a catch-all.  */
268690075Sobrien      if (info)
268790075Sobrien	info->types_allowed = tree_cons (NULL_TREE,
268890075Sobrien					 region->u.allowed.type_list,
268990075Sobrien					 info->types_allowed);
269090075Sobrien
269190075Sobrien      /* If we have definitive information about the type hierarchy,
269290075Sobrien	 then we can tell if the thrown type will pass through the
269390075Sobrien	 filter.  */
269490075Sobrien      if (type_thrown && lang_eh_type_covers)
269590075Sobrien	{
269690075Sobrien	  if (check_handled (region->u.allowed.type_list, type_thrown))
269790075Sobrien	    return RNL_NOT_CAUGHT;
269890075Sobrien	  else
269990075Sobrien	    {
270090075Sobrien	      add_reachable_handler (info, region, region);
270190075Sobrien	      return RNL_CAUGHT;
270290075Sobrien	    }
270390075Sobrien	}
270490075Sobrien
270590075Sobrien      add_reachable_handler (info, region, region);
270690075Sobrien      return RNL_MAYBE_CAUGHT;
270790075Sobrien
270890075Sobrien    case ERT_CATCH:
270990075Sobrien      /* Catch regions are handled by their controling try region.  */
271090075Sobrien      return RNL_NOT_CAUGHT;
271190075Sobrien
271290075Sobrien    case ERT_MUST_NOT_THROW:
271390075Sobrien      /* Here we end our search, since no exceptions may propagate.
271490075Sobrien	 If we've touched down at some landing pad previous, then the
271590075Sobrien	 explicit function call we generated may be used.  Otherwise
271690075Sobrien	 the call is made by the runtime.  */
271790075Sobrien      if (info && info->handlers)
271890075Sobrien	{
271990075Sobrien	  add_reachable_handler (info, region, region);
2720117395Skan	  return RNL_CAUGHT;
272190075Sobrien	}
272290075Sobrien      else
272390075Sobrien	return RNL_BLOCKED;
272490075Sobrien
272590075Sobrien    case ERT_THROW:
272690075Sobrien    case ERT_FIXUP:
272790075Sobrien    case ERT_UNKNOWN:
272890075Sobrien      /* Shouldn't see these here.  */
272990075Sobrien      break;
273090075Sobrien    }
273190075Sobrien
273290075Sobrien  abort ();
273350397Sobrien}
273450397Sobrien
273590075Sobrien/* Retrieve a list of labels of exception handlers which can be
273690075Sobrien   reached by a given insn.  */
273750397Sobrien
273890075Sobrienrtx
273990075Sobrienreachable_handlers (insn)
274050397Sobrien     rtx insn;
274150397Sobrien{
274290075Sobrien  struct reachable_info info;
274390075Sobrien  struct eh_region *region;
274490075Sobrien  tree type_thrown;
274590075Sobrien  int region_number;
274650397Sobrien
274790075Sobrien  if (GET_CODE (insn) == JUMP_INSN
274890075Sobrien      && GET_CODE (PATTERN (insn)) == RESX)
274990075Sobrien    region_number = XINT (PATTERN (insn), 0);
275090075Sobrien  else
275150397Sobrien    {
275290075Sobrien      rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
275390075Sobrien      if (!note || INTVAL (XEXP (note, 0)) <= 0)
275490075Sobrien	return NULL;
275590075Sobrien      region_number = INTVAL (XEXP (note, 0));
275650397Sobrien    }
275750397Sobrien
275890075Sobrien  memset (&info, 0, sizeof (info));
275950397Sobrien
276090075Sobrien  region = cfun->eh->region_array[region_number];
276150397Sobrien
276290075Sobrien  type_thrown = NULL_TREE;
276390075Sobrien  if (GET_CODE (insn) == JUMP_INSN
276490075Sobrien      && GET_CODE (PATTERN (insn)) == RESX)
276590075Sobrien    {
276690075Sobrien      /* A RESX leaves a region instead of entering it.  Thus the
276790075Sobrien	 region itself may have been deleted out from under us.  */
276890075Sobrien      if (region == NULL)
276990075Sobrien	return NULL;
277090075Sobrien      region = region->outer;
277190075Sobrien    }
277290075Sobrien  else if (region->type == ERT_THROW)
277390075Sobrien    {
277490075Sobrien      type_thrown = region->u.throw.type;
277590075Sobrien      region = region->outer;
277690075Sobrien    }
277750397Sobrien
2778117395Skan  while (region)
2779117395Skan    {
2780117395Skan      if (reachable_next_level (region, type_thrown, &info) >= RNL_CAUGHT)
2781117395Skan	break;
2782117395Skan      /* If we have processed one cleanup, there is no point in
2783117395Skan	 processing any more of them.  Each cleanup will have an edge
2784117395Skan	 to the next outer cleanup region, so the flow graph will be
2785117395Skan	 accurate.  */
2786117395Skan      if (region->type == ERT_CLEANUP)
2787117395Skan	region = region->u.cleanup.prev_try;
2788117395Skan      else
2789117395Skan	region = region->outer;
2790117395Skan    }
2791117395Skan
279290075Sobrien  return info.handlers;
279390075Sobrien}
279450397Sobrien
279590075Sobrien/* Determine if the given INSN can throw an exception that is caught
279690075Sobrien   within the function.  */
279790075Sobrien
279890075Sobrienbool
279990075Sobriencan_throw_internal (insn)
280050397Sobrien     rtx insn;
280150397Sobrien{
280290075Sobrien  struct eh_region *region;
280390075Sobrien  tree type_thrown;
280490075Sobrien  rtx note;
280550397Sobrien
280690075Sobrien  if (! INSN_P (insn))
280790075Sobrien    return false;
280850397Sobrien
280990075Sobrien  if (GET_CODE (insn) == INSN
281090075Sobrien      && GET_CODE (PATTERN (insn)) == SEQUENCE)
281190075Sobrien    insn = XVECEXP (PATTERN (insn), 0, 0);
281252284Sobrien
281390075Sobrien  if (GET_CODE (insn) == CALL_INSN
281490075Sobrien      && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
281550397Sobrien    {
281690075Sobrien      int i;
281790075Sobrien      for (i = 0; i < 3; ++i)
281850397Sobrien	{
281990075Sobrien	  rtx sub = XEXP (PATTERN (insn), i);
282090075Sobrien	  for (; sub ; sub = NEXT_INSN (sub))
282190075Sobrien	    if (can_throw_internal (sub))
282290075Sobrien	      return true;
282350397Sobrien	}
282490075Sobrien      return false;
282590075Sobrien    }
282650397Sobrien
282790075Sobrien  /* Every insn that might throw has an EH_REGION note.  */
282890075Sobrien  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
282990075Sobrien  if (!note || INTVAL (XEXP (note, 0)) <= 0)
283090075Sobrien    return false;
283150397Sobrien
283290075Sobrien  region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
283390075Sobrien
283490075Sobrien  type_thrown = NULL_TREE;
283590075Sobrien  if (region->type == ERT_THROW)
283690075Sobrien    {
283790075Sobrien      type_thrown = region->u.throw.type;
283890075Sobrien      region = region->outer;
283950397Sobrien    }
284050397Sobrien
284190075Sobrien  /* If this exception is ignored by each and every containing region,
284290075Sobrien     then control passes straight out.  The runtime may handle some
284390075Sobrien     regions, which also do not require processing internally.  */
284490075Sobrien  for (; region; region = region->outer)
284550397Sobrien    {
284690075Sobrien      enum reachable_code how = reachable_next_level (region, type_thrown, 0);
284790075Sobrien      if (how == RNL_BLOCKED)
284890075Sobrien	return false;
284990075Sobrien      if (how != RNL_NOT_CAUGHT)
2850117395Skan	return true;
285190075Sobrien    }
285250397Sobrien
285390075Sobrien  return false;
285490075Sobrien}
285550397Sobrien
285690075Sobrien/* Determine if the given INSN can throw an exception that is
285790075Sobrien   visible outside the function.  */
285850397Sobrien
285990075Sobrienbool
286090075Sobriencan_throw_external (insn)
286190075Sobrien     rtx insn;
286290075Sobrien{
286390075Sobrien  struct eh_region *region;
286490075Sobrien  tree type_thrown;
286590075Sobrien  rtx note;
286650397Sobrien
286790075Sobrien  if (! INSN_P (insn))
286890075Sobrien    return false;
286990075Sobrien
287090075Sobrien  if (GET_CODE (insn) == INSN
287190075Sobrien      && GET_CODE (PATTERN (insn)) == SEQUENCE)
287290075Sobrien    insn = XVECEXP (PATTERN (insn), 0, 0);
287390075Sobrien
287490075Sobrien  if (GET_CODE (insn) == CALL_INSN
287590075Sobrien      && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
287690075Sobrien    {
287790075Sobrien      int i;
287890075Sobrien      for (i = 0; i < 3; ++i)
287990075Sobrien	{
288090075Sobrien	  rtx sub = XEXP (PATTERN (insn), i);
288190075Sobrien	  for (; sub ; sub = NEXT_INSN (sub))
288290075Sobrien	    if (can_throw_external (sub))
288390075Sobrien	      return true;
288450397Sobrien	}
288590075Sobrien      return false;
288650397Sobrien    }
288790075Sobrien
288890075Sobrien  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
288990075Sobrien  if (!note)
289090075Sobrien    {
289190075Sobrien      /* Calls (and trapping insns) without notes are outside any
289290075Sobrien	 exception handling region in this function.  We have to
289390075Sobrien	 assume it might throw.  Given that the front end and middle
289490075Sobrien	 ends mark known NOTHROW functions, this isn't so wildly
289590075Sobrien	 inaccurate.  */
289690075Sobrien      return (GET_CODE (insn) == CALL_INSN
289790075Sobrien	      || (flag_non_call_exceptions
289890075Sobrien		  && may_trap_p (PATTERN (insn))));
289990075Sobrien    }
290090075Sobrien  if (INTVAL (XEXP (note, 0)) <= 0)
290190075Sobrien    return false;
290290075Sobrien
290390075Sobrien  region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
290490075Sobrien
290590075Sobrien  type_thrown = NULL_TREE;
290690075Sobrien  if (region->type == ERT_THROW)
290790075Sobrien    {
290890075Sobrien      type_thrown = region->u.throw.type;
290990075Sobrien      region = region->outer;
291090075Sobrien    }
291190075Sobrien
291290075Sobrien  /* If the exception is caught or blocked by any containing region,
291390075Sobrien     then it is not seen by any calling function.  */
291490075Sobrien  for (; region ; region = region->outer)
291590075Sobrien    if (reachable_next_level (region, type_thrown, NULL) >= RNL_CAUGHT)
291690075Sobrien      return false;
291790075Sobrien
291890075Sobrien  return true;
291950397Sobrien}
292050397Sobrien
2921117395Skan/* Set current_function_nothrow and cfun->all_throwers_are_sibcalls.  */
292250397Sobrien
2923117395Skanvoid
2924117395Skanset_nothrow_function_flags ()
292550397Sobrien{
292650397Sobrien  rtx insn;
2927117395Skan
2928117395Skan  current_function_nothrow = 1;
292950397Sobrien
2930117395Skan  /* Assume cfun->all_throwers_are_sibcalls until we encounter
2931117395Skan     something that can throw an exception.  We specifically exempt
2932117395Skan     CALL_INSNs that are SIBLING_CALL_P, as these are really jumps,
2933117395Skan     and can't throw.  Most CALL_INSNs are not SIBLING_CALL_P, so this
2934117395Skan     is optimistic.  */
2935117395Skan
2936117395Skan  cfun->all_throwers_are_sibcalls = 1;
2937117395Skan
293890075Sobrien  if (! flag_exceptions)
2939117395Skan    return;
2940117395Skan
294150397Sobrien  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
294290075Sobrien    if (can_throw_external (insn))
2943117395Skan      {
2944117395Skan	current_function_nothrow = 0;
2945117395Skan
2946117395Skan	if (GET_CODE (insn) != CALL_INSN || !SIBLING_CALL_P (insn))
2947117395Skan	  {
2948117395Skan	    cfun->all_throwers_are_sibcalls = 0;
2949117395Skan	    return;
2950117395Skan	  }
2951117395Skan      }
2952117395Skan
295390075Sobrien  for (insn = current_function_epilogue_delay_list; insn;
295490075Sobrien       insn = XEXP (insn, 1))
295590075Sobrien    if (can_throw_external (insn))
2956117395Skan      {
2957117395Skan	current_function_nothrow = 0;
295890075Sobrien
2959117395Skan	if (GET_CODE (insn) != CALL_INSN || !SIBLING_CALL_P (insn))
2960117395Skan	  {
2961117395Skan	    cfun->all_throwers_are_sibcalls = 0;
2962117395Skan	    return;
2963117395Skan	  }
2964117395Skan      }
296550397Sobrien}
296690075Sobrien
296750397Sobrien
296890075Sobrien/* Various hooks for unwind library.  */
296950397Sobrien
297050397Sobrien/* Do any necessary initialization to access arbitrary stack frames.
297150397Sobrien   On the SPARC, this means flushing the register windows.  */
297250397Sobrien
297350397Sobrienvoid
297450397Sobrienexpand_builtin_unwind_init ()
297550397Sobrien{
297650397Sobrien  /* Set this so all the registers get saved in our frame; we need to be
297790075Sobrien     able to copy the saved values for any registers from frames we unwind.  */
297850397Sobrien  current_function_has_nonlocal_label = 1;
297950397Sobrien
298050397Sobrien#ifdef SETUP_FRAME_ADDRESSES
298150397Sobrien  SETUP_FRAME_ADDRESSES ();
298250397Sobrien#endif
298350397Sobrien}
298450397Sobrien
298590075Sobrienrtx
298690075Sobrienexpand_builtin_eh_return_data_regno (arglist)
298790075Sobrien     tree arglist;
298890075Sobrien{
298990075Sobrien  tree which = TREE_VALUE (arglist);
299090075Sobrien  unsigned HOST_WIDE_INT iwhich;
299190075Sobrien
299290075Sobrien  if (TREE_CODE (which) != INTEGER_CST)
299390075Sobrien    {
299490075Sobrien      error ("argument of `__builtin_eh_return_regno' must be constant");
299590075Sobrien      return constm1_rtx;
299690075Sobrien    }
299790075Sobrien
299890075Sobrien  iwhich = tree_low_cst (which, 1);
299990075Sobrien  iwhich = EH_RETURN_DATA_REGNO (iwhich);
300090075Sobrien  if (iwhich == INVALID_REGNUM)
300190075Sobrien    return constm1_rtx;
300290075Sobrien
300390075Sobrien#ifdef DWARF_FRAME_REGNUM
300490075Sobrien  iwhich = DWARF_FRAME_REGNUM (iwhich);
300590075Sobrien#else
300690075Sobrien  iwhich = DBX_REGISTER_NUMBER (iwhich);
300790075Sobrien#endif
300890075Sobrien
300990075Sobrien  return GEN_INT (iwhich);
301090075Sobrien}
301190075Sobrien
301250397Sobrien/* Given a value extracted from the return address register or stack slot,
301350397Sobrien   return the actual address encoded in that value.  */
301450397Sobrien
301550397Sobrienrtx
301650397Sobrienexpand_builtin_extract_return_addr (addr_tree)
301750397Sobrien     tree addr_tree;
301850397Sobrien{
301950397Sobrien  rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
302090075Sobrien
3021117395Skan  if (GET_MODE (addr) != Pmode
3022117395Skan      && GET_MODE (addr) != VOIDmode)
3023117395Skan    {
3024117395Skan#ifdef POINTERS_EXTEND_UNSIGNED
3025117395Skan      addr = convert_memory_address (Pmode, addr);
3026117395Skan#else
3027117395Skan      addr = convert_to_mode (Pmode, addr, 0);
3028117395Skan#endif
3029117395Skan    }
3030117395Skan
303190075Sobrien  /* First mask out any unwanted bits.  */
303290075Sobrien#ifdef MASK_RETURN_ADDR
303396263Sobrien  expand_and (Pmode, addr, MASK_RETURN_ADDR, addr);
303490075Sobrien#endif
303590075Sobrien
303690075Sobrien  /* Then adjust to find the real return address.  */
303790075Sobrien#if defined (RETURN_ADDR_OFFSET)
303890075Sobrien  addr = plus_constant (addr, RETURN_ADDR_OFFSET);
303990075Sobrien#endif
304090075Sobrien
304190075Sobrien  return addr;
304250397Sobrien}
304350397Sobrien
304450397Sobrien/* Given an actual address in addr_tree, do any necessary encoding
304550397Sobrien   and return the value to be stored in the return address register or
304650397Sobrien   stack slot so the epilogue will return to that address.  */
304750397Sobrien
304850397Sobrienrtx
304950397Sobrienexpand_builtin_frob_return_addr (addr_tree)
305050397Sobrien     tree addr_tree;
305150397Sobrien{
305290075Sobrien  rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, 0);
305390075Sobrien
305490075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED
305590075Sobrien  if (GET_MODE (addr) != Pmode)
305690075Sobrien    addr = convert_memory_address (Pmode, addr);
305790075Sobrien#endif
305890075Sobrien
305950397Sobrien#ifdef RETURN_ADDR_OFFSET
306090075Sobrien  addr = force_reg (Pmode, addr);
306150397Sobrien  addr = plus_constant (addr, -RETURN_ADDR_OFFSET);
306250397Sobrien#endif
306390075Sobrien
306450397Sobrien  return addr;
306550397Sobrien}
306650397Sobrien
306790075Sobrien/* Set up the epilogue with the magic bits we'll need to return to the
306890075Sobrien   exception handler.  */
306950397Sobrien
307090075Sobrienvoid
307190075Sobrienexpand_builtin_eh_return (stackadj_tree, handler_tree)
3072117395Skan    tree stackadj_tree ATTRIBUTE_UNUSED;
3073117395Skan    tree handler_tree;
307490075Sobrien{
3075117395Skan  rtx tmp;
307650397Sobrien
3077117395Skan#ifdef EH_RETURN_STACKADJ_RTX
3078117395Skan  tmp = expand_expr (stackadj_tree, cfun->eh->ehr_stackadj, VOIDmode, 0);
3079117395Skan#ifdef POINTERS_EXTEND_UNSIGNED
3080117395Skan  if (GET_MODE (tmp) != Pmode)
3081117395Skan    tmp = convert_memory_address (Pmode, tmp);
3082117395Skan#endif
3083117395Skan  if (!cfun->eh->ehr_stackadj)
3084117395Skan    cfun->eh->ehr_stackadj = copy_to_reg (tmp);
3085117395Skan  else if (tmp != cfun->eh->ehr_stackadj)
3086117395Skan    emit_move_insn (cfun->eh->ehr_stackadj, tmp);
3087117395Skan#endif
308850397Sobrien
3089117395Skan  tmp = expand_expr (handler_tree, cfun->eh->ehr_handler, VOIDmode, 0);
309090075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED
3091117395Skan  if (GET_MODE (tmp) != Pmode)
3092117395Skan    tmp = convert_memory_address (Pmode, tmp);
309350397Sobrien#endif
3094117395Skan  if (!cfun->eh->ehr_handler)
3095117395Skan    cfun->eh->ehr_handler = copy_to_reg (tmp);
3096117395Skan  else if (tmp != cfun->eh->ehr_handler)
3097117395Skan    emit_move_insn (cfun->eh->ehr_handler, tmp);
309850397Sobrien
3099117395Skan  if (!cfun->eh->ehr_label)
3100117395Skan    cfun->eh->ehr_label = gen_label_rtx ();
310190075Sobrien  emit_jump (cfun->eh->ehr_label);
310290075Sobrien}
310390075Sobrien
310490075Sobrienvoid
310590075Sobrienexpand_eh_return ()
310690075Sobrien{
3107117395Skan  rtx around_label;
310890075Sobrien
310990075Sobrien  if (! cfun->eh->ehr_label)
311090075Sobrien    return;
311190075Sobrien
311290075Sobrien  current_function_calls_eh_return = 1;
311390075Sobrien
3114117395Skan#ifdef EH_RETURN_STACKADJ_RTX
3115117395Skan  emit_move_insn (EH_RETURN_STACKADJ_RTX, const0_rtx);
3116117395Skan#endif
3117117395Skan
311890075Sobrien  around_label = gen_label_rtx ();
311990075Sobrien  emit_jump (around_label);
312090075Sobrien
312190075Sobrien  emit_label (cfun->eh->ehr_label);
312290075Sobrien  clobber_return_register ();
312390075Sobrien
3124117395Skan#ifdef EH_RETURN_STACKADJ_RTX
3125117395Skan  emit_move_insn (EH_RETURN_STACKADJ_RTX, cfun->eh->ehr_stackadj);
3126117395Skan#endif
3127117395Skan
312890075Sobrien#ifdef HAVE_eh_return
312990075Sobrien  if (HAVE_eh_return)
3130117395Skan    emit_insn (gen_eh_return (cfun->eh->ehr_handler));
313190075Sobrien  else
313290075Sobrien#endif
313390075Sobrien    {
3134117395Skan#ifdef EH_RETURN_HANDLER_RTX
3135117395Skan      emit_move_insn (EH_RETURN_HANDLER_RTX, cfun->eh->ehr_handler);
3136117395Skan#else
3137117395Skan      error ("__builtin_eh_return not supported on this target");
3138117395Skan#endif
313950397Sobrien    }
314050397Sobrien
314190075Sobrien  emit_label (around_label);
314290075Sobrien}
314390075Sobrien
314490075Sobrien/* In the following functions, we represent entries in the action table
314590075Sobrien   as 1-based indices.  Special cases are:
314652284Sobrien
314790075Sobrien	 0:	null action record, non-null landing pad; implies cleanups
314890075Sobrien	-1:	null action record, null landing pad; implies no action
314990075Sobrien	-2:	no call-site entry; implies must_not_throw
315090075Sobrien	-3:	we have yet to process outer regions
315152284Sobrien
315290075Sobrien   Further, no special cases apply to the "next" field of the record.
315390075Sobrien   For next, 0 means end of list.  */
315490075Sobrien
315590075Sobrienstruct action_record
315690075Sobrien{
315790075Sobrien  int offset;
315890075Sobrien  int filter;
315990075Sobrien  int next;
316090075Sobrien};
316190075Sobrien
316290075Sobrienstatic int
316390075Sobrienaction_record_eq (pentry, pdata)
316490075Sobrien     const PTR pentry;
316590075Sobrien     const PTR pdata;
316690075Sobrien{
316790075Sobrien  const struct action_record *entry = (const struct action_record *) pentry;
316890075Sobrien  const struct action_record *data = (const struct action_record *) pdata;
316990075Sobrien  return entry->filter == data->filter && entry->next == data->next;
317050397Sobrien}
317150397Sobrien
317290075Sobrienstatic hashval_t
317390075Sobrienaction_record_hash (pentry)
317490075Sobrien     const PTR pentry;
317590075Sobrien{
317690075Sobrien  const struct action_record *entry = (const struct action_record *) pentry;
317790075Sobrien  return entry->next * 1009 + entry->filter;
317890075Sobrien}
317950397Sobrien
318090075Sobrienstatic int
318190075Sobrienadd_action_record (ar_hash, filter, next)
318290075Sobrien     htab_t ar_hash;
318390075Sobrien     int filter, next;
318450397Sobrien{
318590075Sobrien  struct action_record **slot, *new, tmp;
318690075Sobrien
318790075Sobrien  tmp.filter = filter;
318890075Sobrien  tmp.next = next;
318990075Sobrien  slot = (struct action_record **) htab_find_slot (ar_hash, &tmp, INSERT);
319090075Sobrien
319190075Sobrien  if ((new = *slot) == NULL)
319290075Sobrien    {
319390075Sobrien      new = (struct action_record *) xmalloc (sizeof (*new));
319490075Sobrien      new->offset = VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) + 1;
319590075Sobrien      new->filter = filter;
319690075Sobrien      new->next = next;
319790075Sobrien      *slot = new;
319890075Sobrien
319990075Sobrien      /* The filter value goes in untouched.  The link to the next
320090075Sobrien	 record is a "self-relative" byte offset, or zero to indicate
320190075Sobrien	 that there is no next record.  So convert the absolute 1 based
320290075Sobrien	 indices we've been carrying around into a displacement.  */
320390075Sobrien
320490075Sobrien      push_sleb128 (&cfun->eh->action_record_data, filter);
320590075Sobrien      if (next)
320690075Sobrien	next -= VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) + 1;
320790075Sobrien      push_sleb128 (&cfun->eh->action_record_data, next);
320890075Sobrien    }
320990075Sobrien
321090075Sobrien  return new->offset;
321150397Sobrien}
321250397Sobrien
321390075Sobrienstatic int
321490075Sobriencollect_one_action_chain (ar_hash, region)
321590075Sobrien     htab_t ar_hash;
321690075Sobrien     struct eh_region *region;
321790075Sobrien{
321890075Sobrien  struct eh_region *c;
321990075Sobrien  int next;
322050397Sobrien
322190075Sobrien  /* If we've reached the top of the region chain, then we have
322290075Sobrien     no actions, and require no landing pad.  */
322390075Sobrien  if (region == NULL)
322490075Sobrien    return -1;
322590075Sobrien
322690075Sobrien  switch (region->type)
322790075Sobrien    {
322890075Sobrien    case ERT_CLEANUP:
322990075Sobrien      /* A cleanup adds a zero filter to the beginning of the chain, but
323090075Sobrien	 there are special cases to look out for.  If there are *only*
323190075Sobrien	 cleanups along a path, then it compresses to a zero action.
323290075Sobrien	 Further, if there are multiple cleanups along a path, we only
323390075Sobrien	 need to represent one of them, as that is enough to trigger
323490075Sobrien	 entry to the landing pad at runtime.  */
323590075Sobrien      next = collect_one_action_chain (ar_hash, region->outer);
323690075Sobrien      if (next <= 0)
323790075Sobrien	return 0;
323890075Sobrien      for (c = region->outer; c ; c = c->outer)
323990075Sobrien	if (c->type == ERT_CLEANUP)
324090075Sobrien	  return next;
324190075Sobrien      return add_action_record (ar_hash, 0, next);
324290075Sobrien
324390075Sobrien    case ERT_TRY:
324490075Sobrien      /* Process the associated catch regions in reverse order.
324590075Sobrien	 If there's a catch-all handler, then we don't need to
324690075Sobrien	 search outer regions.  Use a magic -3 value to record
324790075Sobrien	 that we haven't done the outer search.  */
324890075Sobrien      next = -3;
324990075Sobrien      for (c = region->u.try.last_catch; c ; c = c->u.catch.prev_catch)
325090075Sobrien	{
325190075Sobrien	  if (c->u.catch.type_list == NULL)
325290075Sobrien	    {
325390075Sobrien	      /* Retrieve the filter from the head of the filter list
325490075Sobrien		 where we have stored it (see assign_filter_values).  */
325590075Sobrien	      int filter
325690075Sobrien		= TREE_INT_CST_LOW (TREE_VALUE (c->u.catch.filter_list));
325790075Sobrien
325890075Sobrien	      next = add_action_record (ar_hash, filter, 0);
325990075Sobrien	    }
326090075Sobrien	  else
326190075Sobrien	    {
326290075Sobrien	      /* Once the outer search is done, trigger an action record for
326390075Sobrien                 each filter we have.  */
326490075Sobrien	      tree flt_node;
326590075Sobrien
326690075Sobrien	      if (next == -3)
326790075Sobrien		{
326890075Sobrien		  next = collect_one_action_chain (ar_hash, region->outer);
326990075Sobrien
327090075Sobrien		  /* If there is no next action, terminate the chain.  */
327190075Sobrien		  if (next == -1)
327290075Sobrien		    next = 0;
327390075Sobrien		  /* If all outer actions are cleanups or must_not_throw,
327490075Sobrien		     we'll have no action record for it, since we had wanted
327590075Sobrien		     to encode these states in the call-site record directly.
327690075Sobrien		     Add a cleanup action to the chain to catch these.  */
327790075Sobrien		  else if (next <= 0)
327890075Sobrien		    next = add_action_record (ar_hash, 0, 0);
327990075Sobrien		}
328090075Sobrien
328190075Sobrien	      flt_node = c->u.catch.filter_list;
328290075Sobrien	      for (; flt_node; flt_node = TREE_CHAIN (flt_node))
328390075Sobrien		{
328490075Sobrien		  int filter = TREE_INT_CST_LOW (TREE_VALUE (flt_node));
328590075Sobrien		  next = add_action_record (ar_hash, filter, next);
328690075Sobrien		}
328790075Sobrien	    }
328890075Sobrien	}
328990075Sobrien      return next;
329090075Sobrien
329190075Sobrien    case ERT_ALLOWED_EXCEPTIONS:
329290075Sobrien      /* An exception specification adds its filter to the
329390075Sobrien	 beginning of the chain.  */
329490075Sobrien      next = collect_one_action_chain (ar_hash, region->outer);
329590075Sobrien      return add_action_record (ar_hash, region->u.allowed.filter,
329690075Sobrien				next < 0 ? 0 : next);
329790075Sobrien
329890075Sobrien    case ERT_MUST_NOT_THROW:
329990075Sobrien      /* A must-not-throw region with no inner handlers or cleanups
330090075Sobrien	 requires no call-site entry.  Note that this differs from
330190075Sobrien	 the no handler or cleanup case in that we do require an lsda
330290075Sobrien	 to be generated.  Return a magic -2 value to record this.  */
330390075Sobrien      return -2;
330490075Sobrien
330590075Sobrien    case ERT_CATCH:
330690075Sobrien    case ERT_THROW:
330790075Sobrien      /* CATCH regions are handled in TRY above.  THROW regions are
330890075Sobrien	 for optimization information only and produce no output.  */
330990075Sobrien      return collect_one_action_chain (ar_hash, region->outer);
331090075Sobrien
331190075Sobrien    default:
331290075Sobrien      abort ();
331390075Sobrien    }
331490075Sobrien}
331590075Sobrien
331690075Sobrienstatic int
331790075Sobrienadd_call_site (landing_pad, action)
331890075Sobrien     rtx landing_pad;
331990075Sobrien     int action;
332050397Sobrien{
332190075Sobrien  struct call_site_record *data = cfun->eh->call_site_data;
332290075Sobrien  int used = cfun->eh->call_site_data_used;
332390075Sobrien  int size = cfun->eh->call_site_data_size;
332450397Sobrien
332590075Sobrien  if (used >= size)
332690075Sobrien    {
332790075Sobrien      size = (size ? size * 2 : 64);
332890075Sobrien      data = (struct call_site_record *)
3329117395Skan	ggc_realloc (data, sizeof (*data) * size);
333090075Sobrien      cfun->eh->call_site_data = data;
333190075Sobrien      cfun->eh->call_site_data_size = size;
333290075Sobrien    }
333390075Sobrien
333490075Sobrien  data[used].landing_pad = landing_pad;
333590075Sobrien  data[used].action = action;
333690075Sobrien
333790075Sobrien  cfun->eh->call_site_data_used = used + 1;
333890075Sobrien
333990075Sobrien  return used + call_site_base;
334050397Sobrien}
334150397Sobrien
334290075Sobrien/* Turn REG_EH_REGION notes back into NOTE_INSN_EH_REGION notes.
334390075Sobrien   The new note numbers will not refer to region numbers, but
334490075Sobrien   instead to call site entries.  */
334590075Sobrien
334652284Sobrienvoid
334790075Sobrienconvert_to_eh_region_ranges ()
334850397Sobrien{
334990075Sobrien  rtx insn, iter, note;
335090075Sobrien  htab_t ar_hash;
335190075Sobrien  int last_action = -3;
335290075Sobrien  rtx last_action_insn = NULL_RTX;
335390075Sobrien  rtx last_landing_pad = NULL_RTX;
335490075Sobrien  rtx first_no_action_insn = NULL_RTX;
335590075Sobrien  int call_site = 0;
335650397Sobrien
335790075Sobrien  if (USING_SJLJ_EXCEPTIONS || cfun->eh->region_tree == NULL)
335852284Sobrien    return;
335950397Sobrien
336090075Sobrien  VARRAY_UCHAR_INIT (cfun->eh->action_record_data, 64, "action_record_data");
336150397Sobrien
336290075Sobrien  ar_hash = htab_create (31, action_record_hash, action_record_eq, free);
336350397Sobrien
336490075Sobrien  for (iter = get_insns (); iter ; iter = NEXT_INSN (iter))
336590075Sobrien    if (INSN_P (iter))
336690075Sobrien      {
336790075Sobrien	struct eh_region *region;
336890075Sobrien	int this_action;
336990075Sobrien	rtx this_landing_pad;
337050397Sobrien
337190075Sobrien	insn = iter;
337290075Sobrien	if (GET_CODE (insn) == INSN
337390075Sobrien	    && GET_CODE (PATTERN (insn)) == SEQUENCE)
337490075Sobrien	  insn = XVECEXP (PATTERN (insn), 0, 0);
337550397Sobrien
337690075Sobrien	note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
337790075Sobrien	if (!note)
337890075Sobrien	  {
337990075Sobrien	    if (! (GET_CODE (insn) == CALL_INSN
338090075Sobrien		   || (flag_non_call_exceptions
338190075Sobrien		       && may_trap_p (PATTERN (insn)))))
338290075Sobrien	      continue;
338390075Sobrien	    this_action = -1;
338490075Sobrien	    region = NULL;
338590075Sobrien	  }
338690075Sobrien	else
338790075Sobrien	  {
338890075Sobrien	    if (INTVAL (XEXP (note, 0)) <= 0)
338990075Sobrien	      continue;
339090075Sobrien	    region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
339190075Sobrien	    this_action = collect_one_action_chain (ar_hash, region);
339290075Sobrien	  }
339350397Sobrien
339490075Sobrien	/* Existence of catch handlers, or must-not-throw regions
339590075Sobrien	   implies that an lsda is needed (even if empty).  */
339690075Sobrien	if (this_action != -1)
339790075Sobrien	  cfun->uses_eh_lsda = 1;
339850397Sobrien
339990075Sobrien	/* Delay creation of region notes for no-action regions
340090075Sobrien	   until we're sure that an lsda will be required.  */
340190075Sobrien	else if (last_action == -3)
340290075Sobrien	  {
340390075Sobrien	    first_no_action_insn = iter;
340490075Sobrien	    last_action = -1;
340590075Sobrien	  }
340650397Sobrien
340790075Sobrien	/* Cleanups and handlers may share action chains but not
340890075Sobrien	   landing pads.  Collect the landing pad for this region.  */
340990075Sobrien	if (this_action >= 0)
341090075Sobrien	  {
341190075Sobrien	    struct eh_region *o;
341290075Sobrien	    for (o = region; ! o->landing_pad ; o = o->outer)
341390075Sobrien	      continue;
341490075Sobrien	    this_landing_pad = o->landing_pad;
341590075Sobrien	  }
341690075Sobrien	else
341790075Sobrien	  this_landing_pad = NULL_RTX;
341850397Sobrien
341990075Sobrien	/* Differing actions or landing pads implies a change in call-site
342090075Sobrien	   info, which implies some EH_REGION note should be emitted.  */
342190075Sobrien	if (last_action != this_action
342290075Sobrien	    || last_landing_pad != this_landing_pad)
342390075Sobrien	  {
342490075Sobrien	    /* If we'd not seen a previous action (-3) or the previous
342590075Sobrien	       action was must-not-throw (-2), then we do not need an
342690075Sobrien	       end note.  */
342790075Sobrien	    if (last_action >= -1)
342890075Sobrien	      {
342990075Sobrien		/* If we delayed the creation of the begin, do it now.  */
343090075Sobrien		if (first_no_action_insn)
343190075Sobrien		  {
343290075Sobrien		    call_site = add_call_site (NULL_RTX, 0);
343390075Sobrien		    note = emit_note_before (NOTE_INSN_EH_REGION_BEG,
343490075Sobrien					     first_no_action_insn);
343590075Sobrien		    NOTE_EH_HANDLER (note) = call_site;
343690075Sobrien		    first_no_action_insn = NULL_RTX;
343790075Sobrien		  }
343850397Sobrien
343990075Sobrien		note = emit_note_after (NOTE_INSN_EH_REGION_END,
344090075Sobrien					last_action_insn);
344190075Sobrien		NOTE_EH_HANDLER (note) = call_site;
344290075Sobrien	      }
344352284Sobrien
344490075Sobrien	    /* If the new action is must-not-throw, then no region notes
344590075Sobrien	       are created.  */
344690075Sobrien	    if (this_action >= -1)
344790075Sobrien	      {
344890075Sobrien		call_site = add_call_site (this_landing_pad,
344990075Sobrien					   this_action < 0 ? 0 : this_action);
345090075Sobrien		note = emit_note_before (NOTE_INSN_EH_REGION_BEG, iter);
345190075Sobrien		NOTE_EH_HANDLER (note) = call_site;
345290075Sobrien	      }
345352284Sobrien
345490075Sobrien	    last_action = this_action;
345590075Sobrien	    last_landing_pad = this_landing_pad;
345690075Sobrien	  }
345790075Sobrien	last_action_insn = iter;
345890075Sobrien      }
345952284Sobrien
346090075Sobrien  if (last_action >= -1 && ! first_no_action_insn)
346190075Sobrien    {
346290075Sobrien      note = emit_note_after (NOTE_INSN_EH_REGION_END, last_action_insn);
346390075Sobrien      NOTE_EH_HANDLER (note) = call_site;
346490075Sobrien    }
346552284Sobrien
346690075Sobrien  htab_delete (ar_hash);
346750397Sobrien}
346890075Sobrien
346950397Sobrien
347090075Sobrienstatic void
347190075Sobrienpush_uleb128 (data_area, value)
347290075Sobrien     varray_type *data_area;
347390075Sobrien     unsigned int value;
347490075Sobrien{
347590075Sobrien  do
347690075Sobrien    {
347790075Sobrien      unsigned char byte = value & 0x7f;
347890075Sobrien      value >>= 7;
347990075Sobrien      if (value)
348090075Sobrien	byte |= 0x80;
348190075Sobrien      VARRAY_PUSH_UCHAR (*data_area, byte);
348290075Sobrien    }
348390075Sobrien  while (value);
348490075Sobrien}
348550397Sobrien
348690075Sobrienstatic void
348790075Sobrienpush_sleb128 (data_area, value)
348890075Sobrien     varray_type *data_area;
348990075Sobrien     int value;
349090075Sobrien{
349190075Sobrien  unsigned char byte;
349290075Sobrien  int more;
349350397Sobrien
349490075Sobrien  do
349590075Sobrien    {
349690075Sobrien      byte = value & 0x7f;
349790075Sobrien      value >>= 7;
349890075Sobrien      more = ! ((value == 0 && (byte & 0x40) == 0)
349990075Sobrien		|| (value == -1 && (byte & 0x40) != 0));
350090075Sobrien      if (more)
350190075Sobrien	byte |= 0x80;
350290075Sobrien      VARRAY_PUSH_UCHAR (*data_area, byte);
350390075Sobrien    }
350490075Sobrien  while (more);
350590075Sobrien}
350650397Sobrien
350790075Sobrien
350890075Sobrien#ifndef HAVE_AS_LEB128
350990075Sobrienstatic int
351090075Sobriendw2_size_of_call_site_table ()
351150397Sobrien{
351290075Sobrien  int n = cfun->eh->call_site_data_used;
351390075Sobrien  int size = n * (4 + 4 + 4);
351490075Sobrien  int i;
351550397Sobrien
351690075Sobrien  for (i = 0; i < n; ++i)
351750397Sobrien    {
351890075Sobrien      struct call_site_record *cs = &cfun->eh->call_site_data[i];
351990075Sobrien      size += size_of_uleb128 (cs->action);
352050397Sobrien    }
352190075Sobrien
352290075Sobrien  return size;
352350397Sobrien}
352450397Sobrien
352590075Sobrienstatic int
352690075Sobriensjlj_size_of_call_site_table ()
352790075Sobrien{
352890075Sobrien  int n = cfun->eh->call_site_data_used;
352990075Sobrien  int size = 0;
353090075Sobrien  int i;
353150397Sobrien
353290075Sobrien  for (i = 0; i < n; ++i)
353390075Sobrien    {
353490075Sobrien      struct call_site_record *cs = &cfun->eh->call_site_data[i];
353590075Sobrien      size += size_of_uleb128 (INTVAL (cs->landing_pad));
353690075Sobrien      size += size_of_uleb128 (cs->action);
353790075Sobrien    }
353890075Sobrien
353990075Sobrien  return size;
354090075Sobrien}
354190075Sobrien#endif
354290075Sobrien
354390075Sobrienstatic void
354490075Sobriendw2_output_call_site_table ()
354550397Sobrien{
354690075Sobrien  const char *const function_start_lab
354790075Sobrien    = IDENTIFIER_POINTER (current_function_func_begin_label);
354890075Sobrien  int n = cfun->eh->call_site_data_used;
354990075Sobrien  int i;
355050397Sobrien
355190075Sobrien  for (i = 0; i < n; ++i)
355250397Sobrien    {
355390075Sobrien      struct call_site_record *cs = &cfun->eh->call_site_data[i];
355490075Sobrien      char reg_start_lab[32];
355590075Sobrien      char reg_end_lab[32];
355690075Sobrien      char landing_pad_lab[32];
355790075Sobrien
355890075Sobrien      ASM_GENERATE_INTERNAL_LABEL (reg_start_lab, "LEHB", call_site_base + i);
355990075Sobrien      ASM_GENERATE_INTERNAL_LABEL (reg_end_lab, "LEHE", call_site_base + i);
356090075Sobrien
356190075Sobrien      if (cs->landing_pad)
356290075Sobrien	ASM_GENERATE_INTERNAL_LABEL (landing_pad_lab, "L",
356390075Sobrien				     CODE_LABEL_NUMBER (cs->landing_pad));
356490075Sobrien
356590075Sobrien      /* ??? Perhaps use insn length scaling if the assembler supports
356690075Sobrien	 generic arithmetic.  */
356790075Sobrien      /* ??? Perhaps use attr_length to choose data1 or data2 instead of
356890075Sobrien	 data4 if the function is small enough.  */
356990075Sobrien#ifdef HAVE_AS_LEB128
357090075Sobrien      dw2_asm_output_delta_uleb128 (reg_start_lab, function_start_lab,
357190075Sobrien				    "region %d start", i);
357290075Sobrien      dw2_asm_output_delta_uleb128 (reg_end_lab, reg_start_lab,
357390075Sobrien				    "length");
357490075Sobrien      if (cs->landing_pad)
357590075Sobrien	dw2_asm_output_delta_uleb128 (landing_pad_lab, function_start_lab,
357690075Sobrien				      "landing pad");
357790075Sobrien      else
357890075Sobrien	dw2_asm_output_data_uleb128 (0, "landing pad");
357990075Sobrien#else
358090075Sobrien      dw2_asm_output_delta (4, reg_start_lab, function_start_lab,
358190075Sobrien			    "region %d start", i);
358290075Sobrien      dw2_asm_output_delta (4, reg_end_lab, reg_start_lab, "length");
358390075Sobrien      if (cs->landing_pad)
358490075Sobrien	dw2_asm_output_delta (4, landing_pad_lab, function_start_lab,
358590075Sobrien			      "landing pad");
358690075Sobrien      else
358790075Sobrien	dw2_asm_output_data (4, 0, "landing pad");
358890075Sobrien#endif
358990075Sobrien      dw2_asm_output_data_uleb128 (cs->action, "action");
359050397Sobrien    }
359190075Sobrien
359290075Sobrien  call_site_base += n;
359350397Sobrien}
359450397Sobrien
359590075Sobrienstatic void
359690075Sobriensjlj_output_call_site_table ()
359790075Sobrien{
359890075Sobrien  int n = cfun->eh->call_site_data_used;
359990075Sobrien  int i;
360050397Sobrien
360190075Sobrien  for (i = 0; i < n; ++i)
360290075Sobrien    {
360390075Sobrien      struct call_site_record *cs = &cfun->eh->call_site_data[i];
360490075Sobrien
360590075Sobrien      dw2_asm_output_data_uleb128 (INTVAL (cs->landing_pad),
360690075Sobrien				   "region %d landing pad", i);
360790075Sobrien      dw2_asm_output_data_uleb128 (cs->action, "action");
360890075Sobrien    }
360990075Sobrien
361090075Sobrien  call_site_base += n;
361190075Sobrien}
361290075Sobrien
3613117395Skan/* Tell assembler to switch to the section for the exception handling
3614117395Skan   table.  */
3615117395Skan
361690075Sobrienvoid
3617117395Skandefault_exception_section ()
3618117395Skan{
3619117395Skan  if (targetm.have_named_sections)
3620117395Skan    {
3621117395Skan      int flags;
3622117395Skan#ifdef HAVE_LD_RO_RW_SECTION_MIXING
3623117395Skan      int tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
3624117395Skan
3625117395Skan      flags = (! flag_pic
3626117395Skan	       || ((tt_format & 0x70) != DW_EH_PE_absptr
3627117395Skan		   && (tt_format & 0x70) != DW_EH_PE_aligned))
3628117395Skan	      ? 0 : SECTION_WRITE;
3629117395Skan#else
3630117395Skan      flags = SECTION_WRITE;
3631117395Skan#endif
3632117395Skan      named_section_flags (".gcc_except_table", flags);
3633117395Skan    }
3634117395Skan  else if (flag_pic)
3635117395Skan    data_section ();
3636117395Skan  else
3637117395Skan    readonly_data_section ();
3638117395Skan}
3639117395Skan
3640117395Skanvoid
364190075Sobrienoutput_function_exception_table ()
364250397Sobrien{
364390075Sobrien  int tt_format, cs_format, lp_format, i, n;
364490075Sobrien#ifdef HAVE_AS_LEB128
364590075Sobrien  char ttype_label[32];
364690075Sobrien  char cs_after_size_label[32];
364790075Sobrien  char cs_end_label[32];
364890075Sobrien#else
364990075Sobrien  int call_site_len;
365090075Sobrien#endif
365190075Sobrien  int have_tt_data;
365290075Sobrien  int tt_format_size = 0;
365350397Sobrien
365490075Sobrien  /* Not all functions need anything.  */
365590075Sobrien  if (! cfun->uses_eh_lsda)
365650397Sobrien    return;
365750397Sobrien
365890075Sobrien#ifdef IA64_UNWIND_INFO
365990075Sobrien  fputs ("\t.personality\t", asm_out_file);
366090075Sobrien  output_addr_const (asm_out_file, eh_personality_libfunc);
366190075Sobrien  fputs ("\n\t.handlerdata\n", asm_out_file);
366290075Sobrien  /* Note that varasm still thinks we're in the function's code section.
366390075Sobrien     The ".endp" directive that will immediately follow will take us back.  */
366490075Sobrien#else
366590075Sobrien  (*targetm.asm_out.exception_section) ();
366690075Sobrien#endif
366750397Sobrien
366890075Sobrien  have_tt_data = (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) > 0
366990075Sobrien		  || VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) > 0);
367050397Sobrien
367190075Sobrien  /* Indicate the format of the @TType entries.  */
367290075Sobrien  if (! have_tt_data)
367390075Sobrien    tt_format = DW_EH_PE_omit;
367490075Sobrien  else
367590075Sobrien    {
367690075Sobrien      tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
367790075Sobrien#ifdef HAVE_AS_LEB128
3678117395Skan      ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT",
3679117395Skan				   current_function_funcdef_no);
368090075Sobrien#endif
368190075Sobrien      tt_format_size = size_of_encoded_value (tt_format);
368250397Sobrien
368390075Sobrien      assemble_align (tt_format_size * BITS_PER_UNIT);
368490075Sobrien    }
368550397Sobrien
3686117395Skan  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LLSDA",
3687117395Skan			     current_function_funcdef_no);
368850397Sobrien
368990075Sobrien  /* The LSDA header.  */
369050397Sobrien
369190075Sobrien  /* Indicate the format of the landing pad start pointer.  An omitted
369290075Sobrien     field implies @LPStart == @Start.  */
369390075Sobrien  /* Currently we always put @LPStart == @Start.  This field would
369490075Sobrien     be most useful in moving the landing pads completely out of
369590075Sobrien     line to another section, but it could also be used to minimize
369690075Sobrien     the size of uleb128 landing pad offsets.  */
369790075Sobrien  lp_format = DW_EH_PE_omit;
369890075Sobrien  dw2_asm_output_data (1, lp_format, "@LPStart format (%s)",
369990075Sobrien		       eh_data_format_name (lp_format));
370050397Sobrien
370190075Sobrien  /* @LPStart pointer would go here.  */
370250397Sobrien
370390075Sobrien  dw2_asm_output_data (1, tt_format, "@TType format (%s)",
370490075Sobrien		       eh_data_format_name (tt_format));
370550397Sobrien
370690075Sobrien#ifndef HAVE_AS_LEB128
370790075Sobrien  if (USING_SJLJ_EXCEPTIONS)
370890075Sobrien    call_site_len = sjlj_size_of_call_site_table ();
370990075Sobrien  else
371090075Sobrien    call_site_len = dw2_size_of_call_site_table ();
371190075Sobrien#endif
371290075Sobrien
371390075Sobrien  /* A pc-relative 4-byte displacement to the @TType data.  */
371490075Sobrien  if (have_tt_data)
371590075Sobrien    {
371690075Sobrien#ifdef HAVE_AS_LEB128
371790075Sobrien      char ttype_after_disp_label[32];
371890075Sobrien      ASM_GENERATE_INTERNAL_LABEL (ttype_after_disp_label, "LLSDATTD",
3719117395Skan				   current_function_funcdef_no);
372090075Sobrien      dw2_asm_output_delta_uleb128 (ttype_label, ttype_after_disp_label,
372190075Sobrien				    "@TType base offset");
372290075Sobrien      ASM_OUTPUT_LABEL (asm_out_file, ttype_after_disp_label);
372390075Sobrien#else
372490075Sobrien      /* Ug.  Alignment queers things.  */
372590075Sobrien      unsigned int before_disp, after_disp, last_disp, disp;
372690075Sobrien
372790075Sobrien      before_disp = 1 + 1;
372890075Sobrien      after_disp = (1 + size_of_uleb128 (call_site_len)
372990075Sobrien		    + call_site_len
373090075Sobrien		    + VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data)
373190075Sobrien		    + (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data)
373290075Sobrien		       * tt_format_size));
373390075Sobrien
373490075Sobrien      disp = after_disp;
373590075Sobrien      do
373690075Sobrien	{
373790075Sobrien	  unsigned int disp_size, pad;
373890075Sobrien
373990075Sobrien	  last_disp = disp;
374090075Sobrien	  disp_size = size_of_uleb128 (disp);
374190075Sobrien	  pad = before_disp + disp_size + after_disp;
374290075Sobrien	  if (pad % tt_format_size)
374390075Sobrien	    pad = tt_format_size - (pad % tt_format_size);
374490075Sobrien	  else
374590075Sobrien	    pad = 0;
374690075Sobrien	  disp = after_disp + pad;
374790075Sobrien	}
374890075Sobrien      while (disp != last_disp);
374990075Sobrien
375090075Sobrien      dw2_asm_output_data_uleb128 (disp, "@TType base offset");
375190075Sobrien#endif
375290075Sobrien    }
375390075Sobrien
375490075Sobrien  /* Indicate the format of the call-site offsets.  */
375590075Sobrien#ifdef HAVE_AS_LEB128
375690075Sobrien  cs_format = DW_EH_PE_uleb128;
375790075Sobrien#else
375890075Sobrien  cs_format = DW_EH_PE_udata4;
375990075Sobrien#endif
376090075Sobrien  dw2_asm_output_data (1, cs_format, "call-site format (%s)",
376190075Sobrien		       eh_data_format_name (cs_format));
376290075Sobrien
376390075Sobrien#ifdef HAVE_AS_LEB128
376490075Sobrien  ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label, "LLSDACSB",
3765117395Skan			       current_function_funcdef_no);
376690075Sobrien  ASM_GENERATE_INTERNAL_LABEL (cs_end_label, "LLSDACSE",
3767117395Skan			       current_function_funcdef_no);
376890075Sobrien  dw2_asm_output_delta_uleb128 (cs_end_label, cs_after_size_label,
376990075Sobrien				"Call-site table length");
377090075Sobrien  ASM_OUTPUT_LABEL (asm_out_file, cs_after_size_label);
377190075Sobrien  if (USING_SJLJ_EXCEPTIONS)
377290075Sobrien    sjlj_output_call_site_table ();
377390075Sobrien  else
377490075Sobrien    dw2_output_call_site_table ();
377590075Sobrien  ASM_OUTPUT_LABEL (asm_out_file, cs_end_label);
377690075Sobrien#else
377790075Sobrien  dw2_asm_output_data_uleb128 (call_site_len,"Call-site table length");
377890075Sobrien  if (USING_SJLJ_EXCEPTIONS)
377990075Sobrien    sjlj_output_call_site_table ();
378090075Sobrien  else
378190075Sobrien    dw2_output_call_site_table ();
378290075Sobrien#endif
378390075Sobrien
378490075Sobrien  /* ??? Decode and interpret the data for flag_debug_asm.  */
378590075Sobrien  n = VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data);
378690075Sobrien  for (i = 0; i < n; ++i)
378790075Sobrien    dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->action_record_data, i),
378890075Sobrien			 (i ? NULL : "Action record table"));
378990075Sobrien
379090075Sobrien  if (have_tt_data)
379190075Sobrien    assemble_align (tt_format_size * BITS_PER_UNIT);
379290075Sobrien
379390075Sobrien  i = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data);
379490075Sobrien  while (i-- > 0)
379590075Sobrien    {
379690075Sobrien      tree type = VARRAY_TREE (cfun->eh->ttype_data, i);
379790075Sobrien      rtx value;
379890075Sobrien
379990075Sobrien      if (type == NULL_TREE)
380090075Sobrien	type = integer_zero_node;
380190075Sobrien      else
380290075Sobrien	type = lookup_type_for_runtime (type);
380390075Sobrien
380490075Sobrien      value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
380590075Sobrien      if (tt_format == DW_EH_PE_absptr || tt_format == DW_EH_PE_aligned)
380690075Sobrien	assemble_integer (value, tt_format_size,
380790075Sobrien			  tt_format_size * BITS_PER_UNIT, 1);
380890075Sobrien      else
3809117395Skan	dw2_asm_output_encoded_addr_rtx (tt_format, value, NULL);
381090075Sobrien    }
381190075Sobrien
381290075Sobrien#ifdef HAVE_AS_LEB128
381390075Sobrien  if (have_tt_data)
381490075Sobrien      ASM_OUTPUT_LABEL (asm_out_file, ttype_label);
381590075Sobrien#endif
381690075Sobrien
381790075Sobrien  /* ??? Decode and interpret the data for flag_debug_asm.  */
381890075Sobrien  n = VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data);
381990075Sobrien  for (i = 0; i < n; ++i)
382090075Sobrien    dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->ehspec_data, i),
382190075Sobrien			 (i ? NULL : "Exception specification table"));
382290075Sobrien
382390075Sobrien  function_section (current_function_decl);
3824117395Skan}
382590075Sobrien
3826117395Skan#include "gt-except.h"
3827