xref: /dflybsd-src/contrib/gcc-8.0/gcc/except.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
138fd1498Szrj /* Implements exception handling.
238fd1498Szrj    Copyright (C) 1989-2018 Free Software Foundation, Inc.
338fd1498Szrj    Contributed by Mike Stump <mrs@cygnus.com>.
438fd1498Szrj 
538fd1498Szrj This file is part of GCC.
638fd1498Szrj 
738fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
838fd1498Szrj the terms of the GNU General Public License as published by the Free
938fd1498Szrj Software Foundation; either version 3, or (at your option) any later
1038fd1498Szrj version.
1138fd1498Szrj 
1238fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1338fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1438fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1538fd1498Szrj for more details.
1638fd1498Szrj 
1738fd1498Szrj You should have received a copy of the GNU General Public License
1838fd1498Szrj along with GCC; see the file COPYING3.  If not see
1938fd1498Szrj <http://www.gnu.org/licenses/>.  */
2038fd1498Szrj 
2138fd1498Szrj 
2238fd1498Szrj /* An exception is an event that can be "thrown" from within a
2338fd1498Szrj    function.  This event can then be "caught" by the callers of
2438fd1498Szrj    the function.
2538fd1498Szrj 
2638fd1498Szrj    The representation of exceptions changes several times during
2738fd1498Szrj    the compilation process:
2838fd1498Szrj 
2938fd1498Szrj    In the beginning, in the front end, we have the GENERIC trees
3038fd1498Szrj    TRY_CATCH_EXPR, TRY_FINALLY_EXPR, WITH_CLEANUP_EXPR,
3138fd1498Szrj    CLEANUP_POINT_EXPR, CATCH_EXPR, and EH_FILTER_EXPR.
3238fd1498Szrj 
3338fd1498Szrj    During initial gimplification (gimplify.c) these are lowered
3438fd1498Szrj    to the GIMPLE_TRY, GIMPLE_CATCH, and GIMPLE_EH_FILTER nodes.
3538fd1498Szrj    The WITH_CLEANUP_EXPR and CLEANUP_POINT_EXPR nodes are converted
3638fd1498Szrj    into GIMPLE_TRY_FINALLY nodes; the others are a more direct 1-1
3738fd1498Szrj    conversion.
3838fd1498Szrj 
3938fd1498Szrj    During pass_lower_eh (tree-eh.c) we record the nested structure
4038fd1498Szrj    of the TRY nodes in EH_REGION nodes in CFUN->EH->REGION_TREE.
4138fd1498Szrj    We expand the eh_protect_cleanup_actions langhook into MUST_NOT_THROW
4238fd1498Szrj    regions at this time.  We can then flatten the statements within
4338fd1498Szrj    the TRY nodes to straight-line code.  Statements that had been within
4438fd1498Szrj    TRY nodes that can throw are recorded within CFUN->EH->THROW_STMT_TABLE,
4538fd1498Szrj    so that we may remember what action is supposed to be taken if
4638fd1498Szrj    a given statement does throw.  During this lowering process,
4738fd1498Szrj    we create an EH_LANDING_PAD node for each EH_REGION that has
4838fd1498Szrj    some code within the function that needs to be executed if a
4938fd1498Szrj    throw does happen.  We also create RESX statements that are
5038fd1498Szrj    used to transfer control from an inner EH_REGION to an outer
5138fd1498Szrj    EH_REGION.  We also create EH_DISPATCH statements as placeholders
5238fd1498Szrj    for a runtime type comparison that should be made in order to
5338fd1498Szrj    select the action to perform among different CATCH and EH_FILTER
5438fd1498Szrj    regions.
5538fd1498Szrj 
5638fd1498Szrj    During pass_lower_eh_dispatch (tree-eh.c), which is run after
5738fd1498Szrj    all inlining is complete, we are able to run assign_filter_values,
5838fd1498Szrj    which allows us to map the set of types manipulated by all of the
5938fd1498Szrj    CATCH and EH_FILTER regions to a set of integers.  This set of integers
6038fd1498Szrj    will be how the exception runtime communicates with the code generated
6138fd1498Szrj    within the function.  We then expand the GIMPLE_EH_DISPATCH statements
6238fd1498Szrj    to a switch or conditional branches that use the argument provided by
6338fd1498Szrj    the runtime (__builtin_eh_filter) and the set of integers we computed
6438fd1498Szrj    in assign_filter_values.
6538fd1498Szrj 
6638fd1498Szrj    During pass_lower_resx (tree-eh.c), which is run near the end
6738fd1498Szrj    of optimization, we expand RESX statements.  If the eh region
6838fd1498Szrj    that is outer to the RESX statement is a MUST_NOT_THROW, then
6938fd1498Szrj    the RESX expands to some form of abort statement.  If the eh
7038fd1498Szrj    region that is outer to the RESX statement is within the current
7138fd1498Szrj    function, then the RESX expands to a bookkeeping call
7238fd1498Szrj    (__builtin_eh_copy_values) and a goto.  Otherwise, the next
7338fd1498Szrj    handler for the exception must be within a function somewhere
7438fd1498Szrj    up the call chain, so we call back into the exception runtime
7538fd1498Szrj    (__builtin_unwind_resume).
7638fd1498Szrj 
7738fd1498Szrj    During pass_expand (cfgexpand.c), we generate REG_EH_REGION notes
7838fd1498Szrj    that create an rtl to eh_region mapping that corresponds to the
7938fd1498Szrj    gimple to eh_region mapping that had been recorded in the
8038fd1498Szrj    THROW_STMT_TABLE.
8138fd1498Szrj 
8238fd1498Szrj    Then, via finish_eh_generation, we generate the real landing pads
8338fd1498Szrj    to which the runtime will actually transfer control.  These new
8438fd1498Szrj    landing pads perform whatever bookkeeping is needed by the target
8538fd1498Szrj    backend in order to resume execution within the current function.
8638fd1498Szrj    Each of these new landing pads falls through into the post_landing_pad
8738fd1498Szrj    label which had been used within the CFG up to this point.  All
8838fd1498Szrj    exception edges within the CFG are redirected to the new landing pads.
8938fd1498Szrj    If the target uses setjmp to implement exceptions, the various extra
9038fd1498Szrj    calls into the runtime to register and unregister the current stack
9138fd1498Szrj    frame are emitted at this time.
9238fd1498Szrj 
9338fd1498Szrj    During pass_convert_to_eh_region_ranges (except.c), we transform
9438fd1498Szrj    the REG_EH_REGION notes attached to individual insns into
9538fd1498Szrj    non-overlapping ranges of insns bounded by NOTE_INSN_EH_REGION_BEG
9638fd1498Szrj    and NOTE_INSN_EH_REGION_END.  Each insn within such ranges has the
9738fd1498Szrj    same associated action within the exception region tree, meaning
9838fd1498Szrj    that (1) the exception is caught by the same landing pad within the
9938fd1498Szrj    current function, (2) the exception is blocked by the runtime with
10038fd1498Szrj    a MUST_NOT_THROW region, or (3) the exception is not handled at all
10138fd1498Szrj    within the current function.
10238fd1498Szrj 
10338fd1498Szrj    Finally, during assembly generation, we call
10438fd1498Szrj    output_function_exception_table (except.c) to emit the tables with
10538fd1498Szrj    which the exception runtime can determine if a given stack frame
10638fd1498Szrj    handles a given exception, and if so what filter value to provide
10738fd1498Szrj    to the function when the non-local control transfer is effected.
10838fd1498Szrj    If the target uses dwarf2 unwinding to implement exceptions, then
10938fd1498Szrj    output_call_frame_info (dwarf2out.c) emits the required unwind data.  */
11038fd1498Szrj 
11138fd1498Szrj 
11238fd1498Szrj #include "config.h"
11338fd1498Szrj #include "system.h"
11438fd1498Szrj #include "coretypes.h"
11538fd1498Szrj #include "backend.h"
11638fd1498Szrj #include "target.h"
11738fd1498Szrj #include "rtl.h"
11838fd1498Szrj #include "tree.h"
11938fd1498Szrj #include "cfghooks.h"
12038fd1498Szrj #include "tree-pass.h"
12138fd1498Szrj #include "memmodel.h"
12238fd1498Szrj #include "tm_p.h"
12338fd1498Szrj #include "stringpool.h"
12438fd1498Szrj #include "expmed.h"
12538fd1498Szrj #include "optabs.h"
12638fd1498Szrj #include "emit-rtl.h"
12738fd1498Szrj #include "cgraph.h"
12838fd1498Szrj #include "diagnostic.h"
12938fd1498Szrj #include "fold-const.h"
13038fd1498Szrj #include "stor-layout.h"
13138fd1498Szrj #include "explow.h"
13238fd1498Szrj #include "stmt.h"
13338fd1498Szrj #include "expr.h"
13438fd1498Szrj #include "calls.h"
13538fd1498Szrj #include "libfuncs.h"
13638fd1498Szrj #include "except.h"
13738fd1498Szrj #include "output.h"
13838fd1498Szrj #include "dwarf2asm.h"
13938fd1498Szrj #include "dwarf2out.h"
14038fd1498Szrj #include "common/common-target.h"
14138fd1498Szrj #include "langhooks.h"
14238fd1498Szrj #include "cfgrtl.h"
14338fd1498Szrj #include "tree-pretty-print.h"
14438fd1498Szrj #include "cfgloop.h"
14538fd1498Szrj #include "builtins.h"
14638fd1498Szrj #include "tree-hash-traits.h"
14738fd1498Szrj 
14838fd1498Szrj static GTY(()) int call_site_base;
14938fd1498Szrj 
15038fd1498Szrj static GTY(()) hash_map<tree_hash, tree> *type_to_runtime_map;
15138fd1498Szrj 
15238fd1498Szrj static GTY(()) tree setjmp_fn;
15338fd1498Szrj 
15438fd1498Szrj /* Describe the SjLj_Function_Context structure.  */
15538fd1498Szrj static GTY(()) tree sjlj_fc_type_node;
15638fd1498Szrj static int sjlj_fc_call_site_ofs;
15738fd1498Szrj static int sjlj_fc_data_ofs;
15838fd1498Szrj static int sjlj_fc_personality_ofs;
15938fd1498Szrj static int sjlj_fc_lsda_ofs;
16038fd1498Szrj static int sjlj_fc_jbuf_ofs;
16138fd1498Szrj 
16238fd1498Szrj 
16338fd1498Szrj struct GTY(()) call_site_record_d
16438fd1498Szrj {
16538fd1498Szrj   rtx landing_pad;
16638fd1498Szrj   int action;
16738fd1498Szrj };
16838fd1498Szrj 
16938fd1498Szrj /* In the following structure and associated functions,
17038fd1498Szrj    we represent entries in the action table as 1-based indices.
17138fd1498Szrj    Special cases are:
17238fd1498Szrj 
17338fd1498Szrj 	 0:	null action record, non-null landing pad; implies cleanups
17438fd1498Szrj 	-1:	null action record, null landing pad; implies no action
17538fd1498Szrj 	-2:	no call-site entry; implies must_not_throw
17638fd1498Szrj 	-3:	we have yet to process outer regions
17738fd1498Szrj 
17838fd1498Szrj    Further, no special cases apply to the "next" field of the record.
17938fd1498Szrj    For next, 0 means end of list.  */
18038fd1498Szrj 
18138fd1498Szrj struct action_record
18238fd1498Szrj {
18338fd1498Szrj   int offset;
18438fd1498Szrj   int filter;
18538fd1498Szrj   int next;
18638fd1498Szrj };
18738fd1498Szrj 
18838fd1498Szrj /* Hashtable helpers.  */
18938fd1498Szrj 
19038fd1498Szrj struct action_record_hasher : free_ptr_hash <action_record>
19138fd1498Szrj {
19238fd1498Szrj   static inline hashval_t hash (const action_record *);
19338fd1498Szrj   static inline bool equal (const action_record *, const action_record *);
19438fd1498Szrj };
19538fd1498Szrj 
19638fd1498Szrj inline hashval_t
hash(const action_record * entry)19738fd1498Szrj action_record_hasher::hash (const action_record *entry)
19838fd1498Szrj {
19938fd1498Szrj   return entry->next * 1009 + entry->filter;
20038fd1498Szrj }
20138fd1498Szrj 
20238fd1498Szrj inline bool
equal(const action_record * entry,const action_record * data)20338fd1498Szrj action_record_hasher::equal (const action_record *entry,
20438fd1498Szrj 			     const action_record *data)
20538fd1498Szrj {
20638fd1498Szrj   return entry->filter == data->filter && entry->next == data->next;
20738fd1498Szrj }
20838fd1498Szrj 
20938fd1498Szrj typedef hash_table<action_record_hasher> action_hash_type;
21038fd1498Szrj 
21138fd1498Szrj static bool get_eh_region_and_lp_from_rtx (const_rtx, eh_region *,
21238fd1498Szrj 					   eh_landing_pad *);
21338fd1498Szrj 
21438fd1498Szrj static void dw2_build_landing_pads (void);
21538fd1498Szrj 
21638fd1498Szrj static int collect_one_action_chain (action_hash_type *, eh_region);
21738fd1498Szrj static int add_call_site (rtx, int, int);
21838fd1498Szrj 
21938fd1498Szrj static void push_uleb128 (vec<uchar, va_gc> **, unsigned int);
22038fd1498Szrj static void push_sleb128 (vec<uchar, va_gc> **, int);
22138fd1498Szrj static int dw2_size_of_call_site_table (int);
22238fd1498Szrj static int sjlj_size_of_call_site_table (void);
22338fd1498Szrj static void dw2_output_call_site_table (int, int);
22438fd1498Szrj static void sjlj_output_call_site_table (void);
22538fd1498Szrj 
22638fd1498Szrj 
22738fd1498Szrj void
init_eh(void)22838fd1498Szrj init_eh (void)
22938fd1498Szrj {
23038fd1498Szrj   if (! flag_exceptions)
23138fd1498Szrj     return;
23238fd1498Szrj 
23338fd1498Szrj   type_to_runtime_map = hash_map<tree_hash, tree>::create_ggc (31);
23438fd1498Szrj 
23538fd1498Szrj   /* Create the SjLj_Function_Context structure.  This should match
23638fd1498Szrj      the definition in unwind-sjlj.c.  */
23738fd1498Szrj   if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
23838fd1498Szrj     {
23938fd1498Szrj       tree f_jbuf, f_per, f_lsda, f_prev, f_cs, f_data, tmp;
24038fd1498Szrj 
24138fd1498Szrj       sjlj_fc_type_node = lang_hooks.types.make_type (RECORD_TYPE);
24238fd1498Szrj 
24338fd1498Szrj       f_prev = build_decl (BUILTINS_LOCATION,
24438fd1498Szrj 			   FIELD_DECL, get_identifier ("__prev"),
24538fd1498Szrj 			   build_pointer_type (sjlj_fc_type_node));
24638fd1498Szrj       DECL_FIELD_CONTEXT (f_prev) = sjlj_fc_type_node;
24738fd1498Szrj 
24838fd1498Szrj       f_cs = build_decl (BUILTINS_LOCATION,
24938fd1498Szrj 			 FIELD_DECL, get_identifier ("__call_site"),
25038fd1498Szrj 			 integer_type_node);
25138fd1498Szrj       DECL_FIELD_CONTEXT (f_cs) = sjlj_fc_type_node;
25238fd1498Szrj 
25338fd1498Szrj       tmp = build_index_type (size_int (4 - 1));
25438fd1498Szrj       tmp = build_array_type (lang_hooks.types.type_for_mode
25538fd1498Szrj 				(targetm.unwind_word_mode (), 1),
25638fd1498Szrj 			      tmp);
25738fd1498Szrj       f_data = build_decl (BUILTINS_LOCATION,
25838fd1498Szrj 			   FIELD_DECL, get_identifier ("__data"), tmp);
25938fd1498Szrj       DECL_FIELD_CONTEXT (f_data) = sjlj_fc_type_node;
26038fd1498Szrj 
26138fd1498Szrj       f_per = build_decl (BUILTINS_LOCATION,
26238fd1498Szrj 			  FIELD_DECL, get_identifier ("__personality"),
26338fd1498Szrj 			  ptr_type_node);
26438fd1498Szrj       DECL_FIELD_CONTEXT (f_per) = sjlj_fc_type_node;
26538fd1498Szrj 
26638fd1498Szrj       f_lsda = build_decl (BUILTINS_LOCATION,
26738fd1498Szrj 			   FIELD_DECL, get_identifier ("__lsda"),
26838fd1498Szrj 			   ptr_type_node);
26938fd1498Szrj       DECL_FIELD_CONTEXT (f_lsda) = sjlj_fc_type_node;
27038fd1498Szrj 
27138fd1498Szrj #ifdef DONT_USE_BUILTIN_SETJMP
27238fd1498Szrj #ifdef JMP_BUF_SIZE
27338fd1498Szrj       tmp = size_int (JMP_BUF_SIZE - 1);
27438fd1498Szrj #else
27538fd1498Szrj       /* Should be large enough for most systems, if it is not,
27638fd1498Szrj 	 JMP_BUF_SIZE should be defined with the proper value.  It will
27738fd1498Szrj 	 also tend to be larger than necessary for most systems, a more
27838fd1498Szrj 	 optimal port will define JMP_BUF_SIZE.  */
27938fd1498Szrj       tmp = size_int (FIRST_PSEUDO_REGISTER + 2 - 1);
28038fd1498Szrj #endif
28138fd1498Szrj #else
28238fd1498Szrj       /* Compute a minimally sized jump buffer.  We need room to store at
28338fd1498Szrj 	 least 3 pointers - stack pointer, frame pointer and return address.
28438fd1498Szrj 	 Plus for some targets we need room for an extra pointer - in the
28538fd1498Szrj 	 case of MIPS this is the global pointer.  This makes a total of four
28638fd1498Szrj 	 pointers, but to be safe we actually allocate room for 5.
28738fd1498Szrj 
28838fd1498Szrj 	 If pointers are smaller than words then we allocate enough room for
28938fd1498Szrj 	 5 words, just in case the backend needs this much room.  For more
29038fd1498Szrj 	 discussion on this issue see:
29138fd1498Szrj 	 http://gcc.gnu.org/ml/gcc-patches/2014-05/msg00313.html.  */
29238fd1498Szrj       if (POINTER_SIZE > BITS_PER_WORD)
29338fd1498Szrj 	tmp = size_int (5 - 1);
29438fd1498Szrj       else
29538fd1498Szrj 	tmp = size_int ((5 * BITS_PER_WORD / POINTER_SIZE) - 1);
29638fd1498Szrj #endif
29738fd1498Szrj 
29838fd1498Szrj       tmp = build_index_type (tmp);
29938fd1498Szrj       tmp = build_array_type (ptr_type_node, tmp);
30038fd1498Szrj       f_jbuf = build_decl (BUILTINS_LOCATION,
30138fd1498Szrj 			   FIELD_DECL, get_identifier ("__jbuf"), tmp);
30238fd1498Szrj #ifdef DONT_USE_BUILTIN_SETJMP
30338fd1498Szrj       /* We don't know what the alignment requirements of the
30438fd1498Szrj 	 runtime's jmp_buf has.  Overestimate.  */
30538fd1498Szrj       SET_DECL_ALIGN (f_jbuf, BIGGEST_ALIGNMENT);
30638fd1498Szrj       DECL_USER_ALIGN (f_jbuf) = 1;
30738fd1498Szrj #endif
30838fd1498Szrj       DECL_FIELD_CONTEXT (f_jbuf) = sjlj_fc_type_node;
30938fd1498Szrj 
31038fd1498Szrj       TYPE_FIELDS (sjlj_fc_type_node) = f_prev;
31138fd1498Szrj       TREE_CHAIN (f_prev) = f_cs;
31238fd1498Szrj       TREE_CHAIN (f_cs) = f_data;
31338fd1498Szrj       TREE_CHAIN (f_data) = f_per;
31438fd1498Szrj       TREE_CHAIN (f_per) = f_lsda;
31538fd1498Szrj       TREE_CHAIN (f_lsda) = f_jbuf;
31638fd1498Szrj 
31738fd1498Szrj       layout_type (sjlj_fc_type_node);
31838fd1498Szrj 
31938fd1498Szrj       /* Cache the interesting field offsets so that we have
32038fd1498Szrj 	 easy access from rtl.  */
32138fd1498Szrj       sjlj_fc_call_site_ofs
32238fd1498Szrj 	= (tree_to_uhwi (DECL_FIELD_OFFSET (f_cs))
32338fd1498Szrj 	   + tree_to_uhwi (DECL_FIELD_BIT_OFFSET (f_cs)) / BITS_PER_UNIT);
32438fd1498Szrj       sjlj_fc_data_ofs
32538fd1498Szrj 	= (tree_to_uhwi (DECL_FIELD_OFFSET (f_data))
32638fd1498Szrj 	   + tree_to_uhwi (DECL_FIELD_BIT_OFFSET (f_data)) / BITS_PER_UNIT);
32738fd1498Szrj       sjlj_fc_personality_ofs
32838fd1498Szrj 	= (tree_to_uhwi (DECL_FIELD_OFFSET (f_per))
32938fd1498Szrj 	   + tree_to_uhwi (DECL_FIELD_BIT_OFFSET (f_per)) / BITS_PER_UNIT);
33038fd1498Szrj       sjlj_fc_lsda_ofs
33138fd1498Szrj 	= (tree_to_uhwi (DECL_FIELD_OFFSET (f_lsda))
33238fd1498Szrj 	   + tree_to_uhwi (DECL_FIELD_BIT_OFFSET (f_lsda)) / BITS_PER_UNIT);
33338fd1498Szrj       sjlj_fc_jbuf_ofs
33438fd1498Szrj 	= (tree_to_uhwi (DECL_FIELD_OFFSET (f_jbuf))
33538fd1498Szrj 	   + tree_to_uhwi (DECL_FIELD_BIT_OFFSET (f_jbuf)) / BITS_PER_UNIT);
33638fd1498Szrj 
33738fd1498Szrj #ifdef DONT_USE_BUILTIN_SETJMP
33838fd1498Szrj       tmp = build_function_type_list (integer_type_node, TREE_TYPE (f_jbuf),
33938fd1498Szrj 				      NULL);
34038fd1498Szrj       setjmp_fn = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
34138fd1498Szrj 			      get_identifier ("setjmp"), tmp);
34238fd1498Szrj       TREE_PUBLIC (setjmp_fn) = 1;
34338fd1498Szrj       DECL_EXTERNAL (setjmp_fn) = 1;
34438fd1498Szrj       DECL_ASSEMBLER_NAME (setjmp_fn);
34538fd1498Szrj #endif
34638fd1498Szrj     }
34738fd1498Szrj }
34838fd1498Szrj 
34938fd1498Szrj void
init_eh_for_function(void)35038fd1498Szrj init_eh_for_function (void)
35138fd1498Szrj {
35238fd1498Szrj   cfun->eh = ggc_cleared_alloc<eh_status> ();
35338fd1498Szrj 
35438fd1498Szrj   /* Make sure zero'th entries are used.  */
35538fd1498Szrj   vec_safe_push (cfun->eh->region_array, (eh_region)0);
35638fd1498Szrj   vec_safe_push (cfun->eh->lp_array, (eh_landing_pad)0);
35738fd1498Szrj }
35838fd1498Szrj 
35938fd1498Szrj /* Routines to generate the exception tree somewhat directly.
36038fd1498Szrj    These are used from tree-eh.c when processing exception related
36138fd1498Szrj    nodes during tree optimization.  */
36238fd1498Szrj 
36338fd1498Szrj static eh_region
gen_eh_region(enum eh_region_type type,eh_region outer)36438fd1498Szrj gen_eh_region (enum eh_region_type type, eh_region outer)
36538fd1498Szrj {
36638fd1498Szrj   eh_region new_eh;
36738fd1498Szrj 
36838fd1498Szrj   /* Insert a new blank region as a leaf in the tree.  */
36938fd1498Szrj   new_eh = ggc_cleared_alloc<eh_region_d> ();
37038fd1498Szrj   new_eh->type = type;
37138fd1498Szrj   new_eh->outer = outer;
37238fd1498Szrj   if (outer)
37338fd1498Szrj     {
37438fd1498Szrj       new_eh->next_peer = outer->inner;
37538fd1498Szrj       outer->inner = new_eh;
37638fd1498Szrj     }
37738fd1498Szrj   else
37838fd1498Szrj     {
37938fd1498Szrj       new_eh->next_peer = cfun->eh->region_tree;
38038fd1498Szrj       cfun->eh->region_tree = new_eh;
38138fd1498Szrj     }
38238fd1498Szrj 
38338fd1498Szrj   new_eh->index = vec_safe_length (cfun->eh->region_array);
38438fd1498Szrj   vec_safe_push (cfun->eh->region_array, new_eh);
38538fd1498Szrj 
38638fd1498Szrj   /* Copy the language's notion of whether to use __cxa_end_cleanup.  */
38738fd1498Szrj   if (targetm.arm_eabi_unwinder && lang_hooks.eh_use_cxa_end_cleanup)
38838fd1498Szrj     new_eh->use_cxa_end_cleanup = true;
38938fd1498Szrj 
39038fd1498Szrj   return new_eh;
39138fd1498Szrj }
39238fd1498Szrj 
39338fd1498Szrj eh_region
gen_eh_region_cleanup(eh_region outer)39438fd1498Szrj gen_eh_region_cleanup (eh_region outer)
39538fd1498Szrj {
39638fd1498Szrj   return gen_eh_region (ERT_CLEANUP, outer);
39738fd1498Szrj }
39838fd1498Szrj 
39938fd1498Szrj eh_region
gen_eh_region_try(eh_region outer)40038fd1498Szrj gen_eh_region_try (eh_region outer)
40138fd1498Szrj {
40238fd1498Szrj   return gen_eh_region (ERT_TRY, outer);
40338fd1498Szrj }
40438fd1498Szrj 
40538fd1498Szrj eh_catch
gen_eh_region_catch(eh_region t,tree type_or_list)40638fd1498Szrj gen_eh_region_catch (eh_region t, tree type_or_list)
40738fd1498Szrj {
40838fd1498Szrj   eh_catch c, l;
40938fd1498Szrj   tree type_list, type_node;
41038fd1498Szrj 
41138fd1498Szrj   gcc_assert (t->type == ERT_TRY);
41238fd1498Szrj 
41338fd1498Szrj   /* Ensure to always end up with a type list to normalize further
41438fd1498Szrj      processing, then register each type against the runtime types map.  */
41538fd1498Szrj   type_list = type_or_list;
41638fd1498Szrj   if (type_or_list)
41738fd1498Szrj     {
41838fd1498Szrj       if (TREE_CODE (type_or_list) != TREE_LIST)
41938fd1498Szrj 	type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE);
42038fd1498Szrj 
42138fd1498Szrj       type_node = type_list;
42238fd1498Szrj       for (; type_node; type_node = TREE_CHAIN (type_node))
42338fd1498Szrj 	add_type_for_runtime (TREE_VALUE (type_node));
42438fd1498Szrj     }
42538fd1498Szrj 
42638fd1498Szrj   c = ggc_cleared_alloc<eh_catch_d> ();
42738fd1498Szrj   c->type_list = type_list;
42838fd1498Szrj   l = t->u.eh_try.last_catch;
42938fd1498Szrj   c->prev_catch = l;
43038fd1498Szrj   if (l)
43138fd1498Szrj     l->next_catch = c;
43238fd1498Szrj   else
43338fd1498Szrj     t->u.eh_try.first_catch = c;
43438fd1498Szrj   t->u.eh_try.last_catch = c;
43538fd1498Szrj 
43638fd1498Szrj   return c;
43738fd1498Szrj }
43838fd1498Szrj 
43938fd1498Szrj eh_region
gen_eh_region_allowed(eh_region outer,tree allowed)44038fd1498Szrj gen_eh_region_allowed (eh_region outer, tree allowed)
44138fd1498Szrj {
44238fd1498Szrj   eh_region region = gen_eh_region (ERT_ALLOWED_EXCEPTIONS, outer);
44338fd1498Szrj   region->u.allowed.type_list = allowed;
44438fd1498Szrj 
44538fd1498Szrj   for (; allowed ; allowed = TREE_CHAIN (allowed))
44638fd1498Szrj     add_type_for_runtime (TREE_VALUE (allowed));
44738fd1498Szrj 
44838fd1498Szrj   return region;
44938fd1498Szrj }
45038fd1498Szrj 
45138fd1498Szrj eh_region
gen_eh_region_must_not_throw(eh_region outer)45238fd1498Szrj gen_eh_region_must_not_throw (eh_region outer)
45338fd1498Szrj {
45438fd1498Szrj   return gen_eh_region (ERT_MUST_NOT_THROW, outer);
45538fd1498Szrj }
45638fd1498Szrj 
45738fd1498Szrj eh_landing_pad
gen_eh_landing_pad(eh_region region)45838fd1498Szrj gen_eh_landing_pad (eh_region region)
45938fd1498Szrj {
46038fd1498Szrj   eh_landing_pad lp = ggc_cleared_alloc<eh_landing_pad_d> ();
46138fd1498Szrj 
46238fd1498Szrj   lp->next_lp = region->landing_pads;
46338fd1498Szrj   lp->region = region;
46438fd1498Szrj   lp->index = vec_safe_length (cfun->eh->lp_array);
46538fd1498Szrj   region->landing_pads = lp;
46638fd1498Szrj 
46738fd1498Szrj   vec_safe_push (cfun->eh->lp_array, lp);
46838fd1498Szrj 
46938fd1498Szrj   return lp;
47038fd1498Szrj }
47138fd1498Szrj 
47238fd1498Szrj eh_region
get_eh_region_from_number_fn(struct function * ifun,int i)47338fd1498Szrj get_eh_region_from_number_fn (struct function *ifun, int i)
47438fd1498Szrj {
47538fd1498Szrj   return (*ifun->eh->region_array)[i];
47638fd1498Szrj }
47738fd1498Szrj 
47838fd1498Szrj eh_region
get_eh_region_from_number(int i)47938fd1498Szrj get_eh_region_from_number (int i)
48038fd1498Szrj {
48138fd1498Szrj   return get_eh_region_from_number_fn (cfun, i);
48238fd1498Szrj }
48338fd1498Szrj 
48438fd1498Szrj eh_landing_pad
get_eh_landing_pad_from_number_fn(struct function * ifun,int i)48538fd1498Szrj get_eh_landing_pad_from_number_fn (struct function *ifun, int i)
48638fd1498Szrj {
48738fd1498Szrj   return (*ifun->eh->lp_array)[i];
48838fd1498Szrj }
48938fd1498Szrj 
49038fd1498Szrj eh_landing_pad
get_eh_landing_pad_from_number(int i)49138fd1498Szrj get_eh_landing_pad_from_number (int i)
49238fd1498Szrj {
49338fd1498Szrj   return get_eh_landing_pad_from_number_fn (cfun, i);
49438fd1498Szrj }
49538fd1498Szrj 
49638fd1498Szrj eh_region
get_eh_region_from_lp_number_fn(struct function * ifun,int i)49738fd1498Szrj get_eh_region_from_lp_number_fn (struct function *ifun, int i)
49838fd1498Szrj {
49938fd1498Szrj   if (i < 0)
50038fd1498Szrj     return (*ifun->eh->region_array)[-i];
50138fd1498Szrj   else if (i == 0)
50238fd1498Szrj     return NULL;
50338fd1498Szrj   else
50438fd1498Szrj     {
50538fd1498Szrj       eh_landing_pad lp;
50638fd1498Szrj       lp = (*ifun->eh->lp_array)[i];
50738fd1498Szrj       return lp->region;
50838fd1498Szrj     }
50938fd1498Szrj }
51038fd1498Szrj 
51138fd1498Szrj eh_region
get_eh_region_from_lp_number(int i)51238fd1498Szrj get_eh_region_from_lp_number (int i)
51338fd1498Szrj {
51438fd1498Szrj   return get_eh_region_from_lp_number_fn (cfun, i);
51538fd1498Szrj }
51638fd1498Szrj 
51738fd1498Szrj /* Returns true if the current function has exception handling regions.  */
51838fd1498Szrj 
51938fd1498Szrj bool
current_function_has_exception_handlers(void)52038fd1498Szrj current_function_has_exception_handlers (void)
52138fd1498Szrj {
52238fd1498Szrj   return cfun->eh->region_tree != NULL;
52338fd1498Szrj }
52438fd1498Szrj 
52538fd1498Szrj /* A subroutine of duplicate_eh_regions.  Copy the eh_region tree at OLD.
52638fd1498Szrj    Root it at OUTER, and apply LP_OFFSET to the lp numbers.  */
52738fd1498Szrj 
52838fd1498Szrj struct duplicate_eh_regions_data
52938fd1498Szrj {
53038fd1498Szrj   duplicate_eh_regions_map label_map;
53138fd1498Szrj   void *label_map_data;
53238fd1498Szrj   hash_map<void *, void *> *eh_map;
53338fd1498Szrj };
53438fd1498Szrj 
53538fd1498Szrj static void
duplicate_eh_regions_1(struct duplicate_eh_regions_data * data,eh_region old_r,eh_region outer)53638fd1498Szrj duplicate_eh_regions_1 (struct duplicate_eh_regions_data *data,
53738fd1498Szrj 			eh_region old_r, eh_region outer)
53838fd1498Szrj {
53938fd1498Szrj   eh_landing_pad old_lp, new_lp;
54038fd1498Szrj   eh_region new_r;
54138fd1498Szrj 
54238fd1498Szrj   new_r = gen_eh_region (old_r->type, outer);
54338fd1498Szrj   gcc_assert (!data->eh_map->put (old_r, new_r));
54438fd1498Szrj 
54538fd1498Szrj   switch (old_r->type)
54638fd1498Szrj     {
54738fd1498Szrj     case ERT_CLEANUP:
54838fd1498Szrj       break;
54938fd1498Szrj 
55038fd1498Szrj     case ERT_TRY:
55138fd1498Szrj       {
55238fd1498Szrj 	eh_catch oc, nc;
55338fd1498Szrj 	for (oc = old_r->u.eh_try.first_catch; oc ; oc = oc->next_catch)
55438fd1498Szrj 	  {
55538fd1498Szrj 	    /* We should be doing all our region duplication before and
55638fd1498Szrj 	       during inlining, which is before filter lists are created.  */
55738fd1498Szrj 	    gcc_assert (oc->filter_list == NULL);
55838fd1498Szrj 	    nc = gen_eh_region_catch (new_r, oc->type_list);
55938fd1498Szrj 	    nc->label = data->label_map (oc->label, data->label_map_data);
56038fd1498Szrj 	  }
56138fd1498Szrj       }
56238fd1498Szrj       break;
56338fd1498Szrj 
56438fd1498Szrj     case ERT_ALLOWED_EXCEPTIONS:
56538fd1498Szrj       new_r->u.allowed.type_list = old_r->u.allowed.type_list;
56638fd1498Szrj       if (old_r->u.allowed.label)
56738fd1498Szrj 	new_r->u.allowed.label
56838fd1498Szrj 	    = data->label_map (old_r->u.allowed.label, data->label_map_data);
56938fd1498Szrj       else
57038fd1498Szrj 	new_r->u.allowed.label = NULL_TREE;
57138fd1498Szrj       break;
57238fd1498Szrj 
57338fd1498Szrj     case ERT_MUST_NOT_THROW:
57438fd1498Szrj       new_r->u.must_not_throw.failure_loc =
57538fd1498Szrj 	LOCATION_LOCUS (old_r->u.must_not_throw.failure_loc);
57638fd1498Szrj       new_r->u.must_not_throw.failure_decl =
57738fd1498Szrj 	old_r->u.must_not_throw.failure_decl;
57838fd1498Szrj       break;
57938fd1498Szrj     }
58038fd1498Szrj 
58138fd1498Szrj   for (old_lp = old_r->landing_pads; old_lp ; old_lp = old_lp->next_lp)
58238fd1498Szrj     {
58338fd1498Szrj       /* Don't bother copying unused landing pads.  */
58438fd1498Szrj       if (old_lp->post_landing_pad == NULL)
58538fd1498Szrj 	continue;
58638fd1498Szrj 
58738fd1498Szrj       new_lp = gen_eh_landing_pad (new_r);
58838fd1498Szrj       gcc_assert (!data->eh_map->put (old_lp, new_lp));
58938fd1498Szrj 
59038fd1498Szrj       new_lp->post_landing_pad
59138fd1498Szrj 	= data->label_map (old_lp->post_landing_pad, data->label_map_data);
59238fd1498Szrj       EH_LANDING_PAD_NR (new_lp->post_landing_pad) = new_lp->index;
59338fd1498Szrj     }
59438fd1498Szrj 
59538fd1498Szrj   /* Make sure to preserve the original use of __cxa_end_cleanup.  */
59638fd1498Szrj   new_r->use_cxa_end_cleanup = old_r->use_cxa_end_cleanup;
59738fd1498Szrj 
59838fd1498Szrj   for (old_r = old_r->inner; old_r ; old_r = old_r->next_peer)
59938fd1498Szrj     duplicate_eh_regions_1 (data, old_r, new_r);
60038fd1498Szrj }
60138fd1498Szrj 
60238fd1498Szrj /* Duplicate the EH regions from IFUN rooted at COPY_REGION into
60338fd1498Szrj    the current function and root the tree below OUTER_REGION.
60438fd1498Szrj    The special case of COPY_REGION of NULL means all regions.
60538fd1498Szrj    Remap labels using MAP/MAP_DATA callback.  Return a pointer map
60638fd1498Szrj    that allows the caller to remap uses of both EH regions and
60738fd1498Szrj    EH landing pads.  */
60838fd1498Szrj 
60938fd1498Szrj hash_map<void *, void *> *
duplicate_eh_regions(struct function * ifun,eh_region copy_region,int outer_lp,duplicate_eh_regions_map map,void * map_data)61038fd1498Szrj duplicate_eh_regions (struct function *ifun,
61138fd1498Szrj 		      eh_region copy_region, int outer_lp,
61238fd1498Szrj 		      duplicate_eh_regions_map map, void *map_data)
61338fd1498Szrj {
61438fd1498Szrj   struct duplicate_eh_regions_data data;
61538fd1498Szrj   eh_region outer_region;
61638fd1498Szrj 
61738fd1498Szrj   if (flag_checking)
61838fd1498Szrj     verify_eh_tree (ifun);
61938fd1498Szrj 
62038fd1498Szrj   data.label_map = map;
62138fd1498Szrj   data.label_map_data = map_data;
62238fd1498Szrj   data.eh_map = new hash_map<void *, void *>;
62338fd1498Szrj 
62438fd1498Szrj   outer_region = get_eh_region_from_lp_number_fn (cfun, outer_lp);
62538fd1498Szrj 
62638fd1498Szrj   /* Copy all the regions in the subtree.  */
62738fd1498Szrj   if (copy_region)
62838fd1498Szrj     duplicate_eh_regions_1 (&data, copy_region, outer_region);
62938fd1498Szrj   else
63038fd1498Szrj     {
63138fd1498Szrj       eh_region r;
63238fd1498Szrj       for (r = ifun->eh->region_tree; r ; r = r->next_peer)
63338fd1498Szrj 	duplicate_eh_regions_1 (&data, r, outer_region);
63438fd1498Szrj     }
63538fd1498Szrj 
63638fd1498Szrj   if (flag_checking)
63738fd1498Szrj     verify_eh_tree (cfun);
63838fd1498Szrj 
63938fd1498Szrj   return data.eh_map;
64038fd1498Szrj }
64138fd1498Szrj 
64238fd1498Szrj /* Return the region that is outer to both REGION_A and REGION_B in IFUN.  */
64338fd1498Szrj 
64438fd1498Szrj eh_region
eh_region_outermost(struct function * ifun,eh_region region_a,eh_region region_b)64538fd1498Szrj eh_region_outermost (struct function *ifun, eh_region region_a,
64638fd1498Szrj 		     eh_region region_b)
64738fd1498Szrj {
64838fd1498Szrj   gcc_assert (ifun->eh->region_array);
64938fd1498Szrj   gcc_assert (ifun->eh->region_tree);
65038fd1498Szrj 
65138fd1498Szrj   auto_sbitmap b_outer (ifun->eh->region_array->length ());
65238fd1498Szrj   bitmap_clear (b_outer);
65338fd1498Szrj 
65438fd1498Szrj   do
65538fd1498Szrj     {
65638fd1498Szrj       bitmap_set_bit (b_outer, region_b->index);
65738fd1498Szrj       region_b = region_b->outer;
65838fd1498Szrj     }
65938fd1498Szrj   while (region_b);
66038fd1498Szrj 
66138fd1498Szrj   do
66238fd1498Szrj     {
66338fd1498Szrj       if (bitmap_bit_p (b_outer, region_a->index))
66438fd1498Szrj 	break;
66538fd1498Szrj       region_a = region_a->outer;
66638fd1498Szrj     }
66738fd1498Szrj   while (region_a);
66838fd1498Szrj 
66938fd1498Szrj   return region_a;
67038fd1498Szrj }
67138fd1498Szrj 
67238fd1498Szrj void
add_type_for_runtime(tree type)67338fd1498Szrj add_type_for_runtime (tree type)
67438fd1498Szrj {
67538fd1498Szrj   /* If TYPE is NOP_EXPR, it means that it already is a runtime type.  */
67638fd1498Szrj   if (TREE_CODE (type) == NOP_EXPR)
67738fd1498Szrj     return;
67838fd1498Szrj 
67938fd1498Szrj   bool existed = false;
68038fd1498Szrj   tree *slot = &type_to_runtime_map->get_or_insert (type, &existed);
68138fd1498Szrj   if (!existed)
68238fd1498Szrj     *slot = lang_hooks.eh_runtime_type (type);
68338fd1498Szrj }
68438fd1498Szrj 
68538fd1498Szrj tree
lookup_type_for_runtime(tree type)68638fd1498Szrj lookup_type_for_runtime (tree type)
68738fd1498Szrj {
68838fd1498Szrj   /* If TYPE is NOP_EXPR, it means that it already is a runtime type.  */
68938fd1498Szrj   if (TREE_CODE (type) == NOP_EXPR)
69038fd1498Szrj     return type;
69138fd1498Szrj 
69238fd1498Szrj   /* We should have always inserted the data earlier.  */
69338fd1498Szrj   return *type_to_runtime_map->get (type);
69438fd1498Szrj }
69538fd1498Szrj 
69638fd1498Szrj 
69738fd1498Szrj /* Represent an entry in @TTypes for either catch actions
69838fd1498Szrj    or exception filter actions.  */
69938fd1498Szrj struct ttypes_filter {
70038fd1498Szrj   tree t;
70138fd1498Szrj   int filter;
70238fd1498Szrj };
70338fd1498Szrj 
70438fd1498Szrj /* Helper for ttypes_filter hashing.  */
70538fd1498Szrj 
70638fd1498Szrj struct ttypes_filter_hasher : free_ptr_hash <ttypes_filter>
70738fd1498Szrj {
70838fd1498Szrj   typedef tree_node *compare_type;
70938fd1498Szrj   static inline hashval_t hash (const ttypes_filter *);
71038fd1498Szrj   static inline bool equal (const ttypes_filter *, const tree_node *);
71138fd1498Szrj };
71238fd1498Szrj 
71338fd1498Szrj /* Compare ENTRY (a ttypes_filter entry in the hash table) with DATA
71438fd1498Szrj    (a tree) for a @TTypes type node we are thinking about adding.  */
71538fd1498Szrj 
71638fd1498Szrj inline bool
equal(const ttypes_filter * entry,const tree_node * data)71738fd1498Szrj ttypes_filter_hasher::equal (const ttypes_filter *entry, const tree_node *data)
71838fd1498Szrj {
71938fd1498Szrj   return entry->t == data;
72038fd1498Szrj }
72138fd1498Szrj 
72238fd1498Szrj inline hashval_t
hash(const ttypes_filter * entry)72338fd1498Szrj ttypes_filter_hasher::hash (const ttypes_filter *entry)
72438fd1498Szrj {
72538fd1498Szrj   return TREE_HASH (entry->t);
72638fd1498Szrj }
72738fd1498Szrj 
72838fd1498Szrj typedef hash_table<ttypes_filter_hasher> ttypes_hash_type;
72938fd1498Szrj 
73038fd1498Szrj 
73138fd1498Szrj /* Helper for ehspec hashing.  */
73238fd1498Szrj 
73338fd1498Szrj struct ehspec_hasher : free_ptr_hash <ttypes_filter>
73438fd1498Szrj {
73538fd1498Szrj   static inline hashval_t hash (const ttypes_filter *);
73638fd1498Szrj   static inline bool equal (const ttypes_filter *, const ttypes_filter *);
73738fd1498Szrj };
73838fd1498Szrj 
73938fd1498Szrj /* Compare ENTRY with DATA (both struct ttypes_filter) for a @TTypes
74038fd1498Szrj    exception specification list we are thinking about adding.  */
74138fd1498Szrj /* ??? Currently we use the type lists in the order given.  Someone
74238fd1498Szrj    should put these in some canonical order.  */
74338fd1498Szrj 
74438fd1498Szrj inline bool
equal(const ttypes_filter * entry,const ttypes_filter * data)74538fd1498Szrj ehspec_hasher::equal (const ttypes_filter *entry, const ttypes_filter *data)
74638fd1498Szrj {
74738fd1498Szrj   return type_list_equal (entry->t, data->t);
74838fd1498Szrj }
74938fd1498Szrj 
75038fd1498Szrj /* Hash function for exception specification lists.  */
75138fd1498Szrj 
75238fd1498Szrj inline hashval_t
hash(const ttypes_filter * entry)75338fd1498Szrj ehspec_hasher::hash (const ttypes_filter *entry)
75438fd1498Szrj {
75538fd1498Szrj   hashval_t h = 0;
75638fd1498Szrj   tree list;
75738fd1498Szrj 
75838fd1498Szrj   for (list = entry->t; list ; list = TREE_CHAIN (list))
75938fd1498Szrj     h = (h << 5) + (h >> 27) + TREE_HASH (TREE_VALUE (list));
76038fd1498Szrj   return h;
76138fd1498Szrj }
76238fd1498Szrj 
76338fd1498Szrj typedef hash_table<ehspec_hasher> ehspec_hash_type;
76438fd1498Szrj 
76538fd1498Szrj 
76638fd1498Szrj /* Add TYPE (which may be NULL) to cfun->eh->ttype_data, using TYPES_HASH
76738fd1498Szrj    to speed up the search.  Return the filter value to be used.  */
76838fd1498Szrj 
76938fd1498Szrj static int
add_ttypes_entry(ttypes_hash_type * ttypes_hash,tree type)77038fd1498Szrj add_ttypes_entry (ttypes_hash_type *ttypes_hash, tree type)
77138fd1498Szrj {
77238fd1498Szrj   struct ttypes_filter **slot, *n;
77338fd1498Szrj 
77438fd1498Szrj   slot = ttypes_hash->find_slot_with_hash (type, (hashval_t) TREE_HASH (type),
77538fd1498Szrj 					  INSERT);
77638fd1498Szrj 
77738fd1498Szrj   if ((n = *slot) == NULL)
77838fd1498Szrj     {
77938fd1498Szrj       /* Filter value is a 1 based table index.  */
78038fd1498Szrj 
78138fd1498Szrj       n = XNEW (struct ttypes_filter);
78238fd1498Szrj       n->t = type;
78338fd1498Szrj       n->filter = vec_safe_length (cfun->eh->ttype_data) + 1;
78438fd1498Szrj       *slot = n;
78538fd1498Szrj 
78638fd1498Szrj       vec_safe_push (cfun->eh->ttype_data, type);
78738fd1498Szrj     }
78838fd1498Szrj 
78938fd1498Szrj   return n->filter;
79038fd1498Szrj }
79138fd1498Szrj 
79238fd1498Szrj /* Add LIST to cfun->eh->ehspec_data, using EHSPEC_HASH and TYPES_HASH
79338fd1498Szrj    to speed up the search.  Return the filter value to be used.  */
79438fd1498Szrj 
79538fd1498Szrj static int
add_ehspec_entry(ehspec_hash_type * ehspec_hash,ttypes_hash_type * ttypes_hash,tree list)79638fd1498Szrj add_ehspec_entry (ehspec_hash_type *ehspec_hash, ttypes_hash_type *ttypes_hash,
79738fd1498Szrj 		  tree list)
79838fd1498Szrj {
79938fd1498Szrj   struct ttypes_filter **slot, *n;
80038fd1498Szrj   struct ttypes_filter dummy;
80138fd1498Szrj 
80238fd1498Szrj   dummy.t = list;
80338fd1498Szrj   slot = ehspec_hash->find_slot (&dummy, INSERT);
80438fd1498Szrj 
80538fd1498Szrj   if ((n = *slot) == NULL)
80638fd1498Szrj     {
80738fd1498Szrj       int len;
80838fd1498Szrj 
80938fd1498Szrj       if (targetm.arm_eabi_unwinder)
81038fd1498Szrj 	len = vec_safe_length (cfun->eh->ehspec_data.arm_eabi);
81138fd1498Szrj       else
81238fd1498Szrj 	len = vec_safe_length (cfun->eh->ehspec_data.other);
81338fd1498Szrj 
81438fd1498Szrj       /* Filter value is a -1 based byte index into a uleb128 buffer.  */
81538fd1498Szrj 
81638fd1498Szrj       n = XNEW (struct ttypes_filter);
81738fd1498Szrj       n->t = list;
81838fd1498Szrj       n->filter = -(len + 1);
81938fd1498Szrj       *slot = n;
82038fd1498Szrj 
82138fd1498Szrj       /* Generate a 0 terminated list of filter values.  */
82238fd1498Szrj       for (; list ; list = TREE_CHAIN (list))
82338fd1498Szrj 	{
82438fd1498Szrj 	  if (targetm.arm_eabi_unwinder)
82538fd1498Szrj 	    vec_safe_push (cfun->eh->ehspec_data.arm_eabi, TREE_VALUE (list));
82638fd1498Szrj 	  else
82738fd1498Szrj 	    {
82838fd1498Szrj 	      /* Look up each type in the list and encode its filter
82938fd1498Szrj 		 value as a uleb128.  */
83038fd1498Szrj 	      push_uleb128 (&cfun->eh->ehspec_data.other,
83138fd1498Szrj 			    add_ttypes_entry (ttypes_hash, TREE_VALUE (list)));
83238fd1498Szrj 	    }
83338fd1498Szrj 	}
83438fd1498Szrj       if (targetm.arm_eabi_unwinder)
83538fd1498Szrj 	vec_safe_push (cfun->eh->ehspec_data.arm_eabi, NULL_TREE);
83638fd1498Szrj       else
83738fd1498Szrj 	vec_safe_push (cfun->eh->ehspec_data.other, (uchar)0);
83838fd1498Szrj     }
83938fd1498Szrj 
84038fd1498Szrj   return n->filter;
84138fd1498Szrj }
84238fd1498Szrj 
84338fd1498Szrj /* Generate the action filter values to be used for CATCH and
84438fd1498Szrj    ALLOWED_EXCEPTIONS regions.  When using dwarf2 exception regions,
84538fd1498Szrj    we use lots of landing pads, and so every type or list can share
84638fd1498Szrj    the same filter value, which saves table space.  */
84738fd1498Szrj 
84838fd1498Szrj void
assign_filter_values(void)84938fd1498Szrj assign_filter_values (void)
85038fd1498Szrj {
85138fd1498Szrj   int i;
85238fd1498Szrj   eh_region r;
85338fd1498Szrj   eh_catch c;
85438fd1498Szrj 
85538fd1498Szrj   vec_alloc (cfun->eh->ttype_data, 16);
85638fd1498Szrj   if (targetm.arm_eabi_unwinder)
85738fd1498Szrj     vec_alloc (cfun->eh->ehspec_data.arm_eabi, 64);
85838fd1498Szrj   else
85938fd1498Szrj     vec_alloc (cfun->eh->ehspec_data.other, 64);
86038fd1498Szrj 
86138fd1498Szrj   ehspec_hash_type ehspec (31);
86238fd1498Szrj   ttypes_hash_type ttypes (31);
86338fd1498Szrj 
86438fd1498Szrj   for (i = 1; vec_safe_iterate (cfun->eh->region_array, i, &r); ++i)
86538fd1498Szrj     {
86638fd1498Szrj       if (r == NULL)
86738fd1498Szrj 	continue;
86838fd1498Szrj 
86938fd1498Szrj       switch (r->type)
87038fd1498Szrj 	{
87138fd1498Szrj 	case ERT_TRY:
87238fd1498Szrj 	  for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
87338fd1498Szrj 	    {
87438fd1498Szrj 	      /* Whatever type_list is (NULL or true list), we build a list
87538fd1498Szrj 		 of filters for the region.  */
87638fd1498Szrj 	      c->filter_list = NULL_TREE;
87738fd1498Szrj 
87838fd1498Szrj 	      if (c->type_list != NULL)
87938fd1498Szrj 		{
88038fd1498Szrj 		  /* Get a filter value for each of the types caught and store
88138fd1498Szrj 		     them in the region's dedicated list.  */
88238fd1498Szrj 		  tree tp_node = c->type_list;
88338fd1498Szrj 
88438fd1498Szrj 		  for ( ; tp_node; tp_node = TREE_CHAIN (tp_node))
88538fd1498Szrj 		    {
88638fd1498Szrj 		      int flt
88738fd1498Szrj 		       	= add_ttypes_entry (&ttypes, TREE_VALUE (tp_node));
88838fd1498Szrj 		      tree flt_node = build_int_cst (integer_type_node, flt);
88938fd1498Szrj 
89038fd1498Szrj 		      c->filter_list
89138fd1498Szrj 			= tree_cons (NULL_TREE, flt_node, c->filter_list);
89238fd1498Szrj 		    }
89338fd1498Szrj 		}
89438fd1498Szrj 	      else
89538fd1498Szrj 		{
89638fd1498Szrj 		  /* Get a filter value for the NULL list also since it
89738fd1498Szrj 		     will need an action record anyway.  */
89838fd1498Szrj 		  int flt = add_ttypes_entry (&ttypes, NULL);
89938fd1498Szrj 		  tree flt_node = build_int_cst (integer_type_node, flt);
90038fd1498Szrj 
90138fd1498Szrj 		  c->filter_list
90238fd1498Szrj 		    = tree_cons (NULL_TREE, flt_node, NULL);
90338fd1498Szrj 		}
90438fd1498Szrj 	    }
90538fd1498Szrj 	  break;
90638fd1498Szrj 
90738fd1498Szrj 	case ERT_ALLOWED_EXCEPTIONS:
90838fd1498Szrj 	  r->u.allowed.filter
90938fd1498Szrj 	    = add_ehspec_entry (&ehspec, &ttypes, r->u.allowed.type_list);
91038fd1498Szrj 	  break;
91138fd1498Szrj 
91238fd1498Szrj 	default:
91338fd1498Szrj 	  break;
91438fd1498Szrj 	}
91538fd1498Szrj     }
91638fd1498Szrj }
91738fd1498Szrj 
91838fd1498Szrj /* Emit SEQ into basic block just before INSN (that is assumed to be
91938fd1498Szrj    first instruction of some existing BB and return the newly
92038fd1498Szrj    produced block.  */
92138fd1498Szrj static basic_block
emit_to_new_bb_before(rtx_insn * seq,rtx_insn * insn)92238fd1498Szrj emit_to_new_bb_before (rtx_insn *seq, rtx_insn *insn)
92338fd1498Szrj {
92438fd1498Szrj   rtx_insn *last;
92538fd1498Szrj   basic_block bb;
92638fd1498Szrj   edge e;
92738fd1498Szrj   edge_iterator ei;
92838fd1498Szrj 
92938fd1498Szrj   /* If there happens to be a fallthru edge (possibly created by cleanup_cfg
93038fd1498Szrj      call), we don't want it to go into newly created landing pad or other EH
93138fd1498Szrj      construct.  */
93238fd1498Szrj   for (ei = ei_start (BLOCK_FOR_INSN (insn)->preds); (e = ei_safe_edge (ei)); )
93338fd1498Szrj     if (e->flags & EDGE_FALLTHRU)
93438fd1498Szrj       force_nonfallthru (e);
93538fd1498Szrj     else
93638fd1498Szrj       ei_next (&ei);
93738fd1498Szrj   last = emit_insn_before (seq, insn);
93838fd1498Szrj   if (BARRIER_P (last))
93938fd1498Szrj     last = PREV_INSN (last);
94038fd1498Szrj   bb = create_basic_block (seq, last, BLOCK_FOR_INSN (insn)->prev_bb);
94138fd1498Szrj   update_bb_for_insn (bb);
94238fd1498Szrj   bb->flags |= BB_SUPERBLOCK;
94338fd1498Szrj   return bb;
94438fd1498Szrj }
94538fd1498Szrj 
94638fd1498Szrj /* A subroutine of dw2_build_landing_pads, also used for edge splitting
94738fd1498Szrj    at the rtl level.  Emit the code required by the target at a landing
94838fd1498Szrj    pad for the given region.  */
94938fd1498Szrj 
95038fd1498Szrj static void
expand_dw2_landing_pad_for_region(eh_region region)95138fd1498Szrj expand_dw2_landing_pad_for_region (eh_region region)
95238fd1498Szrj {
95338fd1498Szrj   if (targetm.have_exception_receiver ())
95438fd1498Szrj     emit_insn (targetm.gen_exception_receiver ());
95538fd1498Szrj   else if (targetm.have_nonlocal_goto_receiver ())
95638fd1498Szrj     emit_insn (targetm.gen_nonlocal_goto_receiver ());
95738fd1498Szrj   else
95838fd1498Szrj     { /* Nothing */ }
95938fd1498Szrj 
96038fd1498Szrj   if (region->exc_ptr_reg)
96138fd1498Szrj     emit_move_insn (region->exc_ptr_reg,
96238fd1498Szrj 		    gen_rtx_REG (ptr_mode, EH_RETURN_DATA_REGNO (0)));
96338fd1498Szrj   if (region->filter_reg)
96438fd1498Szrj     emit_move_insn (region->filter_reg,
96538fd1498Szrj 		    gen_rtx_REG (targetm.eh_return_filter_mode (),
96638fd1498Szrj 				 EH_RETURN_DATA_REGNO (1)));
96738fd1498Szrj }
96838fd1498Szrj 
96938fd1498Szrj /* Expand the extra code needed at landing pads for dwarf2 unwinding.  */
97038fd1498Szrj 
97138fd1498Szrj static void
dw2_build_landing_pads(void)97238fd1498Szrj dw2_build_landing_pads (void)
97338fd1498Szrj {
97438fd1498Szrj   int i;
97538fd1498Szrj   eh_landing_pad lp;
97638fd1498Szrj   int e_flags = EDGE_FALLTHRU;
97738fd1498Szrj 
97838fd1498Szrj   /* If we're going to partition blocks, we need to be able to add
97938fd1498Szrj      new landing pads later, which means that we need to hold on to
98038fd1498Szrj      the post-landing-pad block.  Prevent it from being merged away.
98138fd1498Szrj      We'll remove this bit after partitioning.  */
98238fd1498Szrj   if (flag_reorder_blocks_and_partition)
98338fd1498Szrj     e_flags |= EDGE_PRESERVE;
98438fd1498Szrj 
98538fd1498Szrj   for (i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i)
98638fd1498Szrj     {
98738fd1498Szrj       basic_block bb;
98838fd1498Szrj       rtx_insn *seq;
98938fd1498Szrj 
99038fd1498Szrj       if (lp == NULL || lp->post_landing_pad == NULL)
99138fd1498Szrj 	continue;
99238fd1498Szrj 
99338fd1498Szrj       start_sequence ();
99438fd1498Szrj 
99538fd1498Szrj       lp->landing_pad = gen_label_rtx ();
99638fd1498Szrj       emit_label (lp->landing_pad);
99738fd1498Szrj       LABEL_PRESERVE_P (lp->landing_pad) = 1;
99838fd1498Szrj 
99938fd1498Szrj       expand_dw2_landing_pad_for_region (lp->region);
100038fd1498Szrj 
100138fd1498Szrj       seq = get_insns ();
100238fd1498Szrj       end_sequence ();
100338fd1498Szrj 
100438fd1498Szrj       bb = emit_to_new_bb_before (seq, label_rtx (lp->post_landing_pad));
100538fd1498Szrj       bb->count = bb->next_bb->count;
100638fd1498Szrj       make_single_succ_edge (bb, bb->next_bb, e_flags);
100738fd1498Szrj       if (current_loops)
100838fd1498Szrj 	{
100938fd1498Szrj 	  struct loop *loop = bb->next_bb->loop_father;
101038fd1498Szrj 	  /* If we created a pre-header block, add the new block to the
101138fd1498Szrj 	     outer loop, otherwise to the loop itself.  */
101238fd1498Szrj 	  if (bb->next_bb == loop->header)
101338fd1498Szrj 	    add_bb_to_loop (bb, loop_outer (loop));
101438fd1498Szrj 	  else
101538fd1498Szrj 	    add_bb_to_loop (bb, loop);
101638fd1498Szrj 	}
101738fd1498Szrj     }
101838fd1498Szrj }
101938fd1498Szrj 
102038fd1498Szrj 
102138fd1498Szrj static vec<int> sjlj_lp_call_site_index;
102238fd1498Szrj 
102338fd1498Szrj /* Process all active landing pads.  Assign each one a compact dispatch
102438fd1498Szrj    index, and a call-site index.  */
102538fd1498Szrj 
102638fd1498Szrj static int
sjlj_assign_call_site_values(void)102738fd1498Szrj sjlj_assign_call_site_values (void)
102838fd1498Szrj {
102938fd1498Szrj   action_hash_type ar_hash (31);
103038fd1498Szrj   int i, disp_index;
103138fd1498Szrj   eh_landing_pad lp;
103238fd1498Szrj 
103338fd1498Szrj   vec_alloc (crtl->eh.action_record_data, 64);
103438fd1498Szrj 
103538fd1498Szrj   disp_index = 0;
103638fd1498Szrj   call_site_base = 1;
103738fd1498Szrj   for (i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i)
103838fd1498Szrj     if (lp && lp->post_landing_pad)
103938fd1498Szrj       {
104038fd1498Szrj 	int action, call_site;
104138fd1498Szrj 
104238fd1498Szrj 	/* First: build the action table.  */
104338fd1498Szrj 	action = collect_one_action_chain (&ar_hash, lp->region);
104438fd1498Szrj 
104538fd1498Szrj 	/* Next: assign call-site values.  If dwarf2 terms, this would be
104638fd1498Szrj 	   the region number assigned by convert_to_eh_region_ranges, but
104738fd1498Szrj 	   handles no-action and must-not-throw differently.  */
104838fd1498Szrj 	/* Map must-not-throw to otherwise unused call-site index 0.  */
104938fd1498Szrj 	if (action == -2)
105038fd1498Szrj 	  call_site = 0;
105138fd1498Szrj 	/* Map no-action to otherwise unused call-site index -1.  */
105238fd1498Szrj 	else if (action == -1)
105338fd1498Szrj 	  call_site = -1;
105438fd1498Szrj 	/* Otherwise, look it up in the table.  */
105538fd1498Szrj 	else
105638fd1498Szrj 	  call_site = add_call_site (GEN_INT (disp_index), action, 0);
105738fd1498Szrj 	sjlj_lp_call_site_index[i] = call_site;
105838fd1498Szrj 
105938fd1498Szrj 	disp_index++;
106038fd1498Szrj       }
106138fd1498Szrj 
106238fd1498Szrj   return disp_index;
106338fd1498Szrj }
106438fd1498Szrj 
106538fd1498Szrj /* Emit code to record the current call-site index before every
106638fd1498Szrj    insn that can throw.  */
106738fd1498Szrj 
106838fd1498Szrj static void
sjlj_mark_call_sites(void)106938fd1498Szrj sjlj_mark_call_sites (void)
107038fd1498Szrj {
107138fd1498Szrj   int last_call_site = -2;
107238fd1498Szrj   rtx_insn *insn;
107338fd1498Szrj   rtx mem;
107438fd1498Szrj 
107538fd1498Szrj   for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
107638fd1498Szrj     {
107738fd1498Szrj       eh_landing_pad lp;
107838fd1498Szrj       eh_region r;
107938fd1498Szrj       bool nothrow;
108038fd1498Szrj       int this_call_site;
108138fd1498Szrj       rtx_insn *before, *p;
108238fd1498Szrj 
108338fd1498Szrj       /* Reset value tracking at extended basic block boundaries.  */
108438fd1498Szrj       if (LABEL_P (insn))
108538fd1498Szrj 	last_call_site = -2;
108638fd1498Szrj 
108738fd1498Szrj       /* If the function allocates dynamic stack space, the context must
108838fd1498Szrj 	 be updated after every allocation/deallocation accordingly.  */
108938fd1498Szrj       if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_UPDATE_SJLJ_CONTEXT)
109038fd1498Szrj 	{
109138fd1498Szrj 	  rtx buf_addr;
109238fd1498Szrj 
109338fd1498Szrj 	  start_sequence ();
109438fd1498Szrj 	  buf_addr = plus_constant (Pmode, XEXP (crtl->eh.sjlj_fc, 0),
109538fd1498Szrj 				    sjlj_fc_jbuf_ofs);
109638fd1498Szrj 	  expand_builtin_update_setjmp_buf (buf_addr);
109738fd1498Szrj 	  p = get_insns ();
109838fd1498Szrj 	  end_sequence ();
109938fd1498Szrj 	  emit_insn_before (p, insn);
110038fd1498Szrj 	}
110138fd1498Szrj 
110238fd1498Szrj       if (! INSN_P (insn))
110338fd1498Szrj 	continue;
110438fd1498Szrj 
110538fd1498Szrj       nothrow = get_eh_region_and_lp_from_rtx (insn, &r, &lp);
110638fd1498Szrj       if (nothrow)
110738fd1498Szrj 	continue;
110838fd1498Szrj       if (lp)
110938fd1498Szrj 	this_call_site = sjlj_lp_call_site_index[lp->index];
111038fd1498Szrj       else if (r == NULL)
111138fd1498Szrj 	{
111238fd1498Szrj 	  /* Calls (and trapping insns) without notes are outside any
111338fd1498Szrj 	     exception handling region in this function.  Mark them as
111438fd1498Szrj 	     no action.  */
111538fd1498Szrj 	  this_call_site = -1;
111638fd1498Szrj 	}
111738fd1498Szrj       else
111838fd1498Szrj 	{
111938fd1498Szrj 	  gcc_assert (r->type == ERT_MUST_NOT_THROW);
112038fd1498Szrj 	  this_call_site = 0;
112138fd1498Szrj 	}
112238fd1498Szrj 
112338fd1498Szrj       if (this_call_site != -1)
112438fd1498Szrj 	crtl->uses_eh_lsda = 1;
112538fd1498Szrj 
112638fd1498Szrj       if (this_call_site == last_call_site)
112738fd1498Szrj 	continue;
112838fd1498Szrj 
112938fd1498Szrj       /* Don't separate a call from it's argument loads.  */
113038fd1498Szrj       before = insn;
113138fd1498Szrj       if (CALL_P (insn))
113238fd1498Szrj 	before = find_first_parameter_load (insn, NULL);
113338fd1498Szrj 
113438fd1498Szrj       start_sequence ();
113538fd1498Szrj       mem = adjust_address (crtl->eh.sjlj_fc, TYPE_MODE (integer_type_node),
113638fd1498Szrj 			    sjlj_fc_call_site_ofs);
113738fd1498Szrj       emit_move_insn (mem, gen_int_mode (this_call_site, GET_MODE (mem)));
113838fd1498Szrj       p = get_insns ();
113938fd1498Szrj       end_sequence ();
114038fd1498Szrj 
114138fd1498Szrj       emit_insn_before (p, before);
114238fd1498Szrj       last_call_site = this_call_site;
114338fd1498Szrj     }
114438fd1498Szrj }
114538fd1498Szrj 
114638fd1498Szrj /* Construct the SjLj_Function_Context.  */
114738fd1498Szrj 
114838fd1498Szrj static void
sjlj_emit_function_enter(rtx_code_label * dispatch_label)114938fd1498Szrj sjlj_emit_function_enter (rtx_code_label *dispatch_label)
115038fd1498Szrj {
115138fd1498Szrj   rtx_insn *fn_begin, *seq;
115238fd1498Szrj   rtx fc, mem;
115338fd1498Szrj   bool fn_begin_outside_block;
115438fd1498Szrj   rtx personality = get_personality_function (current_function_decl);
115538fd1498Szrj 
115638fd1498Szrj   fc = crtl->eh.sjlj_fc;
115738fd1498Szrj 
115838fd1498Szrj   start_sequence ();
115938fd1498Szrj 
116038fd1498Szrj   /* We're storing this libcall's address into memory instead of
116138fd1498Szrj      calling it directly.  Thus, we must call assemble_external_libcall
116238fd1498Szrj      here, as we can not depend on emit_library_call to do it for us.  */
116338fd1498Szrj   assemble_external_libcall (personality);
116438fd1498Szrj   mem = adjust_address (fc, Pmode, sjlj_fc_personality_ofs);
116538fd1498Szrj   emit_move_insn (mem, personality);
116638fd1498Szrj 
116738fd1498Szrj   mem = adjust_address (fc, Pmode, sjlj_fc_lsda_ofs);
116838fd1498Szrj   if (crtl->uses_eh_lsda)
116938fd1498Szrj     {
117038fd1498Szrj       char buf[20];
117138fd1498Szrj       rtx sym;
117238fd1498Szrj 
117338fd1498Szrj       ASM_GENERATE_INTERNAL_LABEL (buf, "LLSDA", current_function_funcdef_no);
117438fd1498Szrj       sym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
117538fd1498Szrj       SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_LOCAL;
117638fd1498Szrj       emit_move_insn (mem, sym);
117738fd1498Szrj     }
117838fd1498Szrj   else
117938fd1498Szrj     emit_move_insn (mem, const0_rtx);
118038fd1498Szrj 
118138fd1498Szrj   if (dispatch_label)
118238fd1498Szrj     {
118338fd1498Szrj       rtx addr = plus_constant (Pmode, XEXP (fc, 0), sjlj_fc_jbuf_ofs);
118438fd1498Szrj 
118538fd1498Szrj #ifdef DONT_USE_BUILTIN_SETJMP
118638fd1498Szrj       addr = copy_addr_to_reg (addr);
118738fd1498Szrj       addr = convert_memory_address (ptr_mode, addr);
118838fd1498Szrj       tree addr_tree = make_tree (ptr_type_node, addr);
118938fd1498Szrj 
119038fd1498Szrj       tree call_expr = build_call_expr (setjmp_fn, 1, addr_tree);
119138fd1498Szrj       rtx x = expand_call (call_expr, NULL_RTX, false);
119238fd1498Szrj 
119338fd1498Szrj       emit_cmp_and_jump_insns (x, const0_rtx, NE, 0,
119438fd1498Szrj 			       TYPE_MODE (integer_type_node), 0,
119538fd1498Szrj 			       dispatch_label,
119638fd1498Szrj 			       profile_probability::unlikely ());
119738fd1498Szrj #else
119838fd1498Szrj       expand_builtin_setjmp_setup (addr, dispatch_label);
119938fd1498Szrj #endif
120038fd1498Szrj     }
120138fd1498Szrj 
120238fd1498Szrj   emit_library_call (unwind_sjlj_register_libfunc, LCT_NORMAL, VOIDmode,
120338fd1498Szrj 		     XEXP (fc, 0), Pmode);
120438fd1498Szrj 
120538fd1498Szrj   seq = get_insns ();
120638fd1498Szrj   end_sequence ();
120738fd1498Szrj 
120838fd1498Szrj   /* ??? Instead of doing this at the beginning of the function,
120938fd1498Szrj      do this in a block that is at loop level 0 and dominates all
121038fd1498Szrj      can_throw_internal instructions.  */
121138fd1498Szrj 
121238fd1498Szrj   fn_begin_outside_block = true;
121338fd1498Szrj   for (fn_begin = get_insns (); ; fn_begin = NEXT_INSN (fn_begin))
121438fd1498Szrj     if (NOTE_P (fn_begin))
121538fd1498Szrj       {
121638fd1498Szrj 	if (NOTE_KIND (fn_begin) == NOTE_INSN_FUNCTION_BEG)
121738fd1498Szrj 	  break;
121838fd1498Szrj 	else if (NOTE_INSN_BASIC_BLOCK_P (fn_begin))
121938fd1498Szrj 	  fn_begin_outside_block = false;
122038fd1498Szrj       }
122138fd1498Szrj 
122238fd1498Szrj #ifdef DONT_USE_BUILTIN_SETJMP
122338fd1498Szrj   if (dispatch_label)
122438fd1498Szrj     {
122538fd1498Szrj       /* The sequence contains a branch in the middle so we need to force
122638fd1498Szrj 	 the creation of a new basic block by means of BB_SUPERBLOCK.  */
122738fd1498Szrj       if (fn_begin_outside_block)
122838fd1498Szrj 	{
122938fd1498Szrj 	  basic_block bb
123038fd1498Szrj 	    = split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
123138fd1498Szrj 	  if (JUMP_P (BB_END (bb)))
123238fd1498Szrj 	    emit_insn_before (seq, BB_END (bb));
123338fd1498Szrj 	  else
123438fd1498Szrj 	    emit_insn_after (seq, BB_END (bb));
123538fd1498Szrj 	}
123638fd1498Szrj       else
123738fd1498Szrj 	emit_insn_after (seq, fn_begin);
123838fd1498Szrj 
123938fd1498Szrj       single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun))->flags |= BB_SUPERBLOCK;
124038fd1498Szrj       return;
124138fd1498Szrj     }
124238fd1498Szrj #endif
124338fd1498Szrj 
124438fd1498Szrj   if (fn_begin_outside_block)
124538fd1498Szrj     insert_insn_on_edge (seq, single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
124638fd1498Szrj   else
124738fd1498Szrj     emit_insn_after (seq, fn_begin);
124838fd1498Szrj }
124938fd1498Szrj 
125038fd1498Szrj /* Call back from expand_function_end to know where we should put
125138fd1498Szrj    the call to unwind_sjlj_unregister_libfunc if needed.  */
125238fd1498Szrj 
125338fd1498Szrj void
sjlj_emit_function_exit_after(rtx_insn * after)125438fd1498Szrj sjlj_emit_function_exit_after (rtx_insn *after)
125538fd1498Szrj {
125638fd1498Szrj   crtl->eh.sjlj_exit_after = after;
125738fd1498Szrj }
125838fd1498Szrj 
125938fd1498Szrj static void
sjlj_emit_function_exit(void)126038fd1498Szrj sjlj_emit_function_exit (void)
126138fd1498Szrj {
126238fd1498Szrj   rtx_insn *seq, *insn;
126338fd1498Szrj 
126438fd1498Szrj   start_sequence ();
126538fd1498Szrj 
126638fd1498Szrj   emit_library_call (unwind_sjlj_unregister_libfunc, LCT_NORMAL, VOIDmode,
126738fd1498Szrj 		     XEXP (crtl->eh.sjlj_fc, 0), Pmode);
126838fd1498Szrj 
126938fd1498Szrj   seq = get_insns ();
127038fd1498Szrj   end_sequence ();
127138fd1498Szrj 
127238fd1498Szrj   /* ??? Really this can be done in any block at loop level 0 that
127338fd1498Szrj      post-dominates all can_throw_internal instructions.  This is
127438fd1498Szrj      the last possible moment.  */
127538fd1498Szrj 
127638fd1498Szrj   insn = crtl->eh.sjlj_exit_after;
127738fd1498Szrj   if (LABEL_P (insn))
127838fd1498Szrj     insn = NEXT_INSN (insn);
127938fd1498Szrj 
128038fd1498Szrj   emit_insn_after (seq, insn);
128138fd1498Szrj }
128238fd1498Szrj 
128338fd1498Szrj static void
sjlj_emit_dispatch_table(rtx_code_label * dispatch_label,int num_dispatch)128438fd1498Szrj sjlj_emit_dispatch_table (rtx_code_label *dispatch_label, int num_dispatch)
128538fd1498Szrj {
128638fd1498Szrj   scalar_int_mode unwind_word_mode = targetm.unwind_word_mode ();
128738fd1498Szrj   scalar_int_mode filter_mode = targetm.eh_return_filter_mode ();
128838fd1498Szrj   eh_landing_pad lp;
128938fd1498Szrj   rtx mem, fc, exc_ptr_reg, filter_reg;
129038fd1498Szrj   rtx_insn *seq;
129138fd1498Szrj   basic_block bb;
129238fd1498Szrj   eh_region r;
129338fd1498Szrj   int i, disp_index;
129438fd1498Szrj   vec<tree> dispatch_labels = vNULL;
129538fd1498Szrj 
129638fd1498Szrj   fc = crtl->eh.sjlj_fc;
129738fd1498Szrj 
129838fd1498Szrj   start_sequence ();
129938fd1498Szrj 
130038fd1498Szrj   emit_label (dispatch_label);
130138fd1498Szrj 
130238fd1498Szrj #ifndef DONT_USE_BUILTIN_SETJMP
130338fd1498Szrj   expand_builtin_setjmp_receiver (dispatch_label);
130438fd1498Szrj 
130538fd1498Szrj   /* The caller of expand_builtin_setjmp_receiver is responsible for
130638fd1498Szrj      making sure that the label doesn't vanish.  The only other caller
130738fd1498Szrj      is the expander for __builtin_setjmp_receiver, which places this
130838fd1498Szrj      label on the nonlocal_goto_label list.  Since we're modeling these
130938fd1498Szrj      CFG edges more exactly, we can use the forced_labels list instead.  */
131038fd1498Szrj   LABEL_PRESERVE_P (dispatch_label) = 1;
131138fd1498Szrj   vec_safe_push<rtx_insn *> (forced_labels, dispatch_label);
131238fd1498Szrj #endif
131338fd1498Szrj 
131438fd1498Szrj   /* Load up exc_ptr and filter values from the function context.  */
131538fd1498Szrj   mem = adjust_address (fc, unwind_word_mode, sjlj_fc_data_ofs);
131638fd1498Szrj   if (unwind_word_mode != ptr_mode)
131738fd1498Szrj     {
131838fd1498Szrj #ifdef POINTERS_EXTEND_UNSIGNED
131938fd1498Szrj       mem = convert_memory_address (ptr_mode, mem);
132038fd1498Szrj #else
132138fd1498Szrj       mem = convert_to_mode (ptr_mode, mem, 0);
132238fd1498Szrj #endif
132338fd1498Szrj     }
132438fd1498Szrj   exc_ptr_reg = force_reg (ptr_mode, mem);
132538fd1498Szrj 
132638fd1498Szrj   mem = adjust_address (fc, unwind_word_mode,
132738fd1498Szrj 			sjlj_fc_data_ofs + GET_MODE_SIZE (unwind_word_mode));
132838fd1498Szrj   if (unwind_word_mode != filter_mode)
132938fd1498Szrj     mem = convert_to_mode (filter_mode, mem, 0);
133038fd1498Szrj   filter_reg = force_reg (filter_mode, mem);
133138fd1498Szrj 
133238fd1498Szrj   /* Jump to one of the directly reachable regions.  */
133338fd1498Szrj 
133438fd1498Szrj   disp_index = 0;
133538fd1498Szrj   rtx_code_label *first_reachable_label = NULL;
133638fd1498Szrj 
133738fd1498Szrj   /* If there's exactly one call site in the function, don't bother
133838fd1498Szrj      generating a switch statement.  */
133938fd1498Szrj   if (num_dispatch > 1)
134038fd1498Szrj     dispatch_labels.create (num_dispatch);
134138fd1498Szrj 
134238fd1498Szrj   for (i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i)
134338fd1498Szrj     if (lp && lp->post_landing_pad)
134438fd1498Szrj       {
134538fd1498Szrj 	rtx_insn *seq2;
134638fd1498Szrj 	rtx_code_label *label;
134738fd1498Szrj 
134838fd1498Szrj 	start_sequence ();
134938fd1498Szrj 
135038fd1498Szrj 	lp->landing_pad = dispatch_label;
135138fd1498Szrj 
135238fd1498Szrj 	if (num_dispatch > 1)
135338fd1498Szrj 	  {
135438fd1498Szrj 	    tree t_label, case_elt, t;
135538fd1498Szrj 
135638fd1498Szrj 	    t_label = create_artificial_label (UNKNOWN_LOCATION);
135738fd1498Szrj 	    t = build_int_cst (integer_type_node, disp_index);
135838fd1498Szrj 	    case_elt = build_case_label (t, NULL, t_label);
135938fd1498Szrj 	    dispatch_labels.quick_push (case_elt);
136038fd1498Szrj 	    label = jump_target_rtx (t_label);
136138fd1498Szrj 	  }
136238fd1498Szrj 	else
136338fd1498Szrj 	  label = gen_label_rtx ();
136438fd1498Szrj 
136538fd1498Szrj 	if (disp_index == 0)
136638fd1498Szrj 	  first_reachable_label = label;
136738fd1498Szrj 	emit_label (label);
136838fd1498Szrj 
136938fd1498Szrj 	r = lp->region;
137038fd1498Szrj 	if (r->exc_ptr_reg)
137138fd1498Szrj 	  emit_move_insn (r->exc_ptr_reg, exc_ptr_reg);
137238fd1498Szrj 	if (r->filter_reg)
137338fd1498Szrj 	  emit_move_insn (r->filter_reg, filter_reg);
137438fd1498Szrj 
137538fd1498Szrj 	seq2 = get_insns ();
137638fd1498Szrj 	end_sequence ();
137738fd1498Szrj 
137838fd1498Szrj 	rtx_insn *before = label_rtx (lp->post_landing_pad);
137938fd1498Szrj 	bb = emit_to_new_bb_before (seq2, before);
138038fd1498Szrj 	make_single_succ_edge (bb, bb->next_bb, EDGE_FALLTHRU);
138138fd1498Szrj 	if (current_loops)
138238fd1498Szrj 	  {
138338fd1498Szrj 	    struct loop *loop = bb->next_bb->loop_father;
138438fd1498Szrj 	    /* If we created a pre-header block, add the new block to the
138538fd1498Szrj 	       outer loop, otherwise to the loop itself.  */
138638fd1498Szrj 	    if (bb->next_bb == loop->header)
138738fd1498Szrj 	      add_bb_to_loop (bb, loop_outer (loop));
138838fd1498Szrj 	    else
138938fd1498Szrj 	      add_bb_to_loop (bb, loop);
139038fd1498Szrj 	    /* ???  For multiple dispatches we will end up with edges
139138fd1498Szrj 	       from the loop tree root into this loop, making it a
139238fd1498Szrj 	       multiple-entry loop.  Discard all affected loops.  */
139338fd1498Szrj 	    if (num_dispatch > 1)
139438fd1498Szrj 	      {
139538fd1498Szrj 		for (loop = bb->loop_father;
139638fd1498Szrj 		     loop_outer (loop); loop = loop_outer (loop))
139738fd1498Szrj 		  mark_loop_for_removal (loop);
139838fd1498Szrj 	      }
139938fd1498Szrj 	  }
140038fd1498Szrj 
140138fd1498Szrj 	disp_index++;
140238fd1498Szrj       }
140338fd1498Szrj   gcc_assert (disp_index == num_dispatch);
140438fd1498Szrj 
140538fd1498Szrj   if (num_dispatch > 1)
140638fd1498Szrj     {
140738fd1498Szrj       rtx disp = adjust_address (fc, TYPE_MODE (integer_type_node),
140838fd1498Szrj 				 sjlj_fc_call_site_ofs);
140938fd1498Szrj       expand_sjlj_dispatch_table (disp, dispatch_labels);
141038fd1498Szrj     }
141138fd1498Szrj 
141238fd1498Szrj   seq = get_insns ();
141338fd1498Szrj   end_sequence ();
141438fd1498Szrj 
141538fd1498Szrj   bb = emit_to_new_bb_before (seq, first_reachable_label);
141638fd1498Szrj   if (num_dispatch == 1)
141738fd1498Szrj     {
141838fd1498Szrj       make_single_succ_edge (bb, bb->next_bb, EDGE_FALLTHRU);
141938fd1498Szrj       if (current_loops)
142038fd1498Szrj 	{
142138fd1498Szrj 	  struct loop *loop = bb->next_bb->loop_father;
142238fd1498Szrj 	  /* If we created a pre-header block, add the new block to the
142338fd1498Szrj 	     outer loop, otherwise to the loop itself.  */
142438fd1498Szrj 	  if (bb->next_bb == loop->header)
142538fd1498Szrj 	    add_bb_to_loop (bb, loop_outer (loop));
142638fd1498Szrj 	  else
142738fd1498Szrj 	    add_bb_to_loop (bb, loop);
142838fd1498Szrj 	}
142938fd1498Szrj     }
143038fd1498Szrj   else
143138fd1498Szrj     {
143238fd1498Szrj       /* We are not wiring up edges here, but as the dispatcher call
143338fd1498Szrj          is at function begin simply associate the block with the
143438fd1498Szrj 	 outermost (non-)loop.  */
143538fd1498Szrj       if (current_loops)
143638fd1498Szrj 	add_bb_to_loop (bb, current_loops->tree_root);
143738fd1498Szrj     }
143838fd1498Szrj }
143938fd1498Szrj 
144038fd1498Szrj static void
sjlj_build_landing_pads(void)144138fd1498Szrj sjlj_build_landing_pads (void)
144238fd1498Szrj {
144338fd1498Szrj   int num_dispatch;
144438fd1498Szrj 
144538fd1498Szrj   num_dispatch = vec_safe_length (cfun->eh->lp_array);
144638fd1498Szrj   if (num_dispatch == 0)
144738fd1498Szrj     return;
144838fd1498Szrj   sjlj_lp_call_site_index.safe_grow_cleared (num_dispatch);
144938fd1498Szrj 
145038fd1498Szrj   num_dispatch = sjlj_assign_call_site_values ();
145138fd1498Szrj   if (num_dispatch > 0)
145238fd1498Szrj     {
145338fd1498Szrj       rtx_code_label *dispatch_label = gen_label_rtx ();
145438fd1498Szrj       int align = STACK_SLOT_ALIGNMENT (sjlj_fc_type_node,
145538fd1498Szrj 					TYPE_MODE (sjlj_fc_type_node),
145638fd1498Szrj 					TYPE_ALIGN (sjlj_fc_type_node));
145738fd1498Szrj       crtl->eh.sjlj_fc
145838fd1498Szrj 	= assign_stack_local (TYPE_MODE (sjlj_fc_type_node),
145938fd1498Szrj 			      int_size_in_bytes (sjlj_fc_type_node),
146038fd1498Szrj 			      align);
146138fd1498Szrj 
146238fd1498Szrj       sjlj_mark_call_sites ();
146338fd1498Szrj       sjlj_emit_function_enter (dispatch_label);
146438fd1498Szrj       sjlj_emit_dispatch_table (dispatch_label, num_dispatch);
146538fd1498Szrj       sjlj_emit_function_exit ();
146638fd1498Szrj     }
146738fd1498Szrj 
146838fd1498Szrj   /* If we do not have any landing pads, we may still need to register a
146938fd1498Szrj      personality routine and (empty) LSDA to handle must-not-throw regions.  */
147038fd1498Szrj   else if (function_needs_eh_personality (cfun) != eh_personality_none)
147138fd1498Szrj     {
147238fd1498Szrj       int align = STACK_SLOT_ALIGNMENT (sjlj_fc_type_node,
147338fd1498Szrj 					TYPE_MODE (sjlj_fc_type_node),
147438fd1498Szrj 					TYPE_ALIGN (sjlj_fc_type_node));
147538fd1498Szrj       crtl->eh.sjlj_fc
147638fd1498Szrj 	= assign_stack_local (TYPE_MODE (sjlj_fc_type_node),
147738fd1498Szrj 			      int_size_in_bytes (sjlj_fc_type_node),
147838fd1498Szrj 			      align);
147938fd1498Szrj 
148038fd1498Szrj       sjlj_mark_call_sites ();
148138fd1498Szrj       sjlj_emit_function_enter (NULL);
148238fd1498Szrj       sjlj_emit_function_exit ();
148338fd1498Szrj     }
148438fd1498Szrj 
148538fd1498Szrj   sjlj_lp_call_site_index.release ();
148638fd1498Szrj }
148738fd1498Szrj 
148838fd1498Szrj /* Update the sjlj function context.  This function should be called
148938fd1498Szrj    whenever we allocate or deallocate dynamic stack space.  */
149038fd1498Szrj 
149138fd1498Szrj void
update_sjlj_context(void)149238fd1498Szrj update_sjlj_context (void)
149338fd1498Szrj {
149438fd1498Szrj   if (!flag_exceptions)
149538fd1498Szrj     return;
149638fd1498Szrj 
149738fd1498Szrj   emit_note (NOTE_INSN_UPDATE_SJLJ_CONTEXT);
149838fd1498Szrj }
149938fd1498Szrj 
150038fd1498Szrj /* After initial rtl generation, call back to finish generating
150138fd1498Szrj    exception support code.  */
150238fd1498Szrj 
150338fd1498Szrj void
finish_eh_generation(void)150438fd1498Szrj finish_eh_generation (void)
150538fd1498Szrj {
150638fd1498Szrj   basic_block bb;
150738fd1498Szrj 
150838fd1498Szrj   /* Construct the landing pads.  */
150938fd1498Szrj   if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
151038fd1498Szrj     sjlj_build_landing_pads ();
151138fd1498Szrj   else
151238fd1498Szrj     dw2_build_landing_pads ();
151338fd1498Szrj   break_superblocks ();
151438fd1498Szrj 
151538fd1498Szrj   if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ
151638fd1498Szrj       /* Kludge for Alpha (see alpha_gp_save_rtx).  */
151738fd1498Szrj       || single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))->insns.r)
151838fd1498Szrj     commit_edge_insertions ();
151938fd1498Szrj 
152038fd1498Szrj   /* Redirect all EH edges from the post_landing_pad to the landing pad.  */
152138fd1498Szrj   FOR_EACH_BB_FN (bb, cfun)
152238fd1498Szrj     {
152338fd1498Szrj       eh_landing_pad lp;
152438fd1498Szrj       edge_iterator ei;
152538fd1498Szrj       edge e;
152638fd1498Szrj 
152738fd1498Szrj       lp = get_eh_landing_pad_from_rtx (BB_END (bb));
152838fd1498Szrj 
152938fd1498Szrj       FOR_EACH_EDGE (e, ei, bb->succs)
153038fd1498Szrj 	if (e->flags & EDGE_EH)
153138fd1498Szrj 	  break;
153238fd1498Szrj 
153338fd1498Szrj       /* We should not have generated any new throwing insns during this
153438fd1498Szrj 	 pass, and we should not have lost any EH edges, so we only need
153538fd1498Szrj 	 to handle two cases here:
153638fd1498Szrj 	 (1) reachable handler and an existing edge to post-landing-pad,
153738fd1498Szrj 	 (2) no reachable handler and no edge.  */
153838fd1498Szrj       gcc_assert ((lp != NULL) == (e != NULL));
153938fd1498Szrj       if (lp != NULL)
154038fd1498Szrj 	{
154138fd1498Szrj 	  gcc_assert (BB_HEAD (e->dest) == label_rtx (lp->post_landing_pad));
154238fd1498Szrj 
154338fd1498Szrj 	  redirect_edge_succ (e, BLOCK_FOR_INSN (lp->landing_pad));
154438fd1498Szrj 	  e->flags |= (CALL_P (BB_END (bb))
154538fd1498Szrj 		       ? EDGE_ABNORMAL | EDGE_ABNORMAL_CALL
154638fd1498Szrj 		       : EDGE_ABNORMAL);
154738fd1498Szrj 	}
154838fd1498Szrj     }
154938fd1498Szrj }
155038fd1498Szrj 
155138fd1498Szrj /* This section handles removing dead code for flow.  */
155238fd1498Szrj 
155338fd1498Szrj void
remove_eh_landing_pad(eh_landing_pad lp)155438fd1498Szrj remove_eh_landing_pad (eh_landing_pad lp)
155538fd1498Szrj {
155638fd1498Szrj   eh_landing_pad *pp;
155738fd1498Szrj 
155838fd1498Szrj   for (pp = &lp->region->landing_pads; *pp != lp; pp = &(*pp)->next_lp)
155938fd1498Szrj     continue;
156038fd1498Szrj   *pp = lp->next_lp;
156138fd1498Szrj 
156238fd1498Szrj   if (lp->post_landing_pad)
156338fd1498Szrj     EH_LANDING_PAD_NR (lp->post_landing_pad) = 0;
156438fd1498Szrj   (*cfun->eh->lp_array)[lp->index] = NULL;
156538fd1498Szrj }
156638fd1498Szrj 
156738fd1498Szrj /* Splice the EH region at PP from the region tree.  */
156838fd1498Szrj 
156938fd1498Szrj static void
remove_eh_handler_splicer(eh_region * pp)157038fd1498Szrj remove_eh_handler_splicer (eh_region *pp)
157138fd1498Szrj {
157238fd1498Szrj   eh_region region = *pp;
157338fd1498Szrj   eh_landing_pad lp;
157438fd1498Szrj 
157538fd1498Szrj   for (lp = region->landing_pads; lp ; lp = lp->next_lp)
157638fd1498Szrj     {
157738fd1498Szrj       if (lp->post_landing_pad)
157838fd1498Szrj 	EH_LANDING_PAD_NR (lp->post_landing_pad) = 0;
157938fd1498Szrj       (*cfun->eh->lp_array)[lp->index] = NULL;
158038fd1498Szrj     }
158138fd1498Szrj 
158238fd1498Szrj   if (region->inner)
158338fd1498Szrj     {
158438fd1498Szrj       eh_region p, outer;
158538fd1498Szrj       outer = region->outer;
158638fd1498Szrj 
158738fd1498Szrj       *pp = p = region->inner;
158838fd1498Szrj       do
158938fd1498Szrj 	{
159038fd1498Szrj 	  p->outer = outer;
159138fd1498Szrj 	  pp = &p->next_peer;
159238fd1498Szrj 	  p = *pp;
159338fd1498Szrj 	}
159438fd1498Szrj       while (p);
159538fd1498Szrj     }
159638fd1498Szrj   *pp = region->next_peer;
159738fd1498Szrj 
159838fd1498Szrj   (*cfun->eh->region_array)[region->index] = NULL;
159938fd1498Szrj }
160038fd1498Szrj 
160138fd1498Szrj /* Splice a single EH region REGION from the region tree.
160238fd1498Szrj 
160338fd1498Szrj    To unlink REGION, we need to find the pointer to it with a relatively
160438fd1498Szrj    expensive search in REGION's outer region.  If you are going to
160538fd1498Szrj    remove a number of handlers, using remove_unreachable_eh_regions may
160638fd1498Szrj    be a better option.  */
160738fd1498Szrj 
160838fd1498Szrj void
remove_eh_handler(eh_region region)160938fd1498Szrj remove_eh_handler (eh_region region)
161038fd1498Szrj {
161138fd1498Szrj   eh_region *pp, *pp_start, p, outer;
161238fd1498Szrj 
161338fd1498Szrj   outer = region->outer;
161438fd1498Szrj   if (outer)
161538fd1498Szrj     pp_start = &outer->inner;
161638fd1498Szrj   else
161738fd1498Szrj     pp_start = &cfun->eh->region_tree;
161838fd1498Szrj   for (pp = pp_start, p = *pp; p != region; pp = &p->next_peer, p = *pp)
161938fd1498Szrj     continue;
162038fd1498Szrj 
162138fd1498Szrj   remove_eh_handler_splicer (pp);
162238fd1498Szrj }
162338fd1498Szrj 
162438fd1498Szrj /* Worker for remove_unreachable_eh_regions.
162538fd1498Szrj    PP is a pointer to the region to start a region tree depth-first
162638fd1498Szrj    search from.  R_REACHABLE is the set of regions that have to be
162738fd1498Szrj    preserved.  */
162838fd1498Szrj 
162938fd1498Szrj static void
remove_unreachable_eh_regions_worker(eh_region * pp,sbitmap r_reachable)163038fd1498Szrj remove_unreachable_eh_regions_worker (eh_region *pp, sbitmap r_reachable)
163138fd1498Szrj {
163238fd1498Szrj   while (*pp)
163338fd1498Szrj     {
163438fd1498Szrj       eh_region region = *pp;
163538fd1498Szrj       remove_unreachable_eh_regions_worker (&region->inner, r_reachable);
163638fd1498Szrj       if (!bitmap_bit_p (r_reachable, region->index))
163738fd1498Szrj 	remove_eh_handler_splicer (pp);
163838fd1498Szrj       else
163938fd1498Szrj 	pp = &region->next_peer;
164038fd1498Szrj     }
164138fd1498Szrj }
164238fd1498Szrj 
164338fd1498Szrj /* Splice all EH regions *not* marked in R_REACHABLE from the region tree.
164438fd1498Szrj    Do this by traversing the EH tree top-down and splice out regions that
164538fd1498Szrj    are not marked.  By removing regions from the leaves, we avoid costly
164638fd1498Szrj    searches in the region tree.  */
164738fd1498Szrj 
164838fd1498Szrj void
remove_unreachable_eh_regions(sbitmap r_reachable)164938fd1498Szrj remove_unreachable_eh_regions (sbitmap r_reachable)
165038fd1498Szrj {
165138fd1498Szrj   remove_unreachable_eh_regions_worker (&cfun->eh->region_tree, r_reachable);
165238fd1498Szrj }
165338fd1498Szrj 
165438fd1498Szrj /* Invokes CALLBACK for every exception handler landing pad label.
165538fd1498Szrj    Only used by reload hackery; should not be used by new code.  */
165638fd1498Szrj 
165738fd1498Szrj void
for_each_eh_label(void (* callback)(rtx))165838fd1498Szrj for_each_eh_label (void (*callback) (rtx))
165938fd1498Szrj {
166038fd1498Szrj   eh_landing_pad lp;
166138fd1498Szrj   int i;
166238fd1498Szrj 
166338fd1498Szrj   for (i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i)
166438fd1498Szrj     {
166538fd1498Szrj       if (lp)
166638fd1498Szrj 	{
166738fd1498Szrj 	  rtx_code_label *lab = lp->landing_pad;
166838fd1498Szrj 	  if (lab && LABEL_P (lab))
166938fd1498Szrj 	    (*callback) (lab);
167038fd1498Szrj 	}
167138fd1498Szrj     }
167238fd1498Szrj }
167338fd1498Szrj 
167438fd1498Szrj /* Create the REG_EH_REGION note for INSN, given its ECF_FLAGS for a
167538fd1498Szrj    call insn.
167638fd1498Szrj 
167738fd1498Szrj    At the gimple level, we use LP_NR
167838fd1498Szrj        > 0 : The statement transfers to landing pad LP_NR
167938fd1498Szrj        = 0 : The statement is outside any EH region
168038fd1498Szrj        < 0 : The statement is within MUST_NOT_THROW region -LP_NR.
168138fd1498Szrj 
168238fd1498Szrj    At the rtl level, we use LP_NR
168338fd1498Szrj        > 0 : The insn transfers to landing pad LP_NR
168438fd1498Szrj        = 0 : The insn cannot throw
168538fd1498Szrj        < 0 : The insn is within MUST_NOT_THROW region -LP_NR
168638fd1498Szrj        = INT_MIN : The insn cannot throw or execute a nonlocal-goto.
168738fd1498Szrj        missing note: The insn is outside any EH region.
168838fd1498Szrj 
168938fd1498Szrj   ??? This difference probably ought to be avoided.  We could stand
169038fd1498Szrj   to record nothrow for arbitrary gimple statements, and so avoid
169138fd1498Szrj   some moderately complex lookups in stmt_could_throw_p.  Perhaps
169238fd1498Szrj   NOTHROW should be mapped on both sides to INT_MIN.  Perhaps the
169338fd1498Szrj   no-nonlocal-goto property should be recorded elsewhere as a bit
169438fd1498Szrj   on the call_insn directly.  Perhaps we should make more use of
169538fd1498Szrj   attaching the trees to call_insns (reachable via symbol_ref in
169638fd1498Szrj   direct call cases) and just pull the data out of the trees.  */
169738fd1498Szrj 
169838fd1498Szrj void
make_reg_eh_region_note(rtx_insn * insn,int ecf_flags,int lp_nr)169938fd1498Szrj make_reg_eh_region_note (rtx_insn *insn, int ecf_flags, int lp_nr)
170038fd1498Szrj {
170138fd1498Szrj   rtx value;
170238fd1498Szrj   if (ecf_flags & ECF_NOTHROW)
170338fd1498Szrj     value = const0_rtx;
170438fd1498Szrj   else if (lp_nr != 0)
170538fd1498Szrj     value = GEN_INT (lp_nr);
170638fd1498Szrj   else
170738fd1498Szrj     return;
170838fd1498Szrj   add_reg_note (insn, REG_EH_REGION, value);
170938fd1498Szrj }
171038fd1498Szrj 
171138fd1498Szrj /* Create a REG_EH_REGION note for a CALL_INSN that cannot throw
171238fd1498Szrj    nor perform a non-local goto.  Replace the region note if it
171338fd1498Szrj    already exists.  */
171438fd1498Szrj 
171538fd1498Szrj void
make_reg_eh_region_note_nothrow_nononlocal(rtx_insn * insn)171638fd1498Szrj make_reg_eh_region_note_nothrow_nononlocal (rtx_insn *insn)
171738fd1498Szrj {
171838fd1498Szrj   rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
171938fd1498Szrj   rtx intmin = GEN_INT (INT_MIN);
172038fd1498Szrj 
172138fd1498Szrj   if (note != 0)
172238fd1498Szrj     XEXP (note, 0) = intmin;
172338fd1498Szrj   else
172438fd1498Szrj     add_reg_note (insn, REG_EH_REGION, intmin);
172538fd1498Szrj }
172638fd1498Szrj 
172738fd1498Szrj /* Return true if INSN could throw, assuming no REG_EH_REGION note
172838fd1498Szrj    to the contrary.  */
172938fd1498Szrj 
173038fd1498Szrj bool
insn_could_throw_p(const_rtx insn)173138fd1498Szrj insn_could_throw_p (const_rtx insn)
173238fd1498Szrj {
173338fd1498Szrj   if (!flag_exceptions)
173438fd1498Szrj     return false;
173538fd1498Szrj   if (CALL_P (insn))
173638fd1498Szrj     return true;
173738fd1498Szrj   if (INSN_P (insn) && cfun->can_throw_non_call_exceptions)
173838fd1498Szrj     return may_trap_p (PATTERN (insn));
173938fd1498Szrj   return false;
174038fd1498Szrj }
174138fd1498Szrj 
174238fd1498Szrj /* Copy an REG_EH_REGION note to each insn that might throw beginning
174338fd1498Szrj    at FIRST and ending at LAST.  NOTE_OR_INSN is either the source insn
174438fd1498Szrj    to look for a note, or the note itself.  */
174538fd1498Szrj 
174638fd1498Szrj void
copy_reg_eh_region_note_forward(rtx note_or_insn,rtx_insn * first,rtx last)174738fd1498Szrj copy_reg_eh_region_note_forward (rtx note_or_insn, rtx_insn *first, rtx last)
174838fd1498Szrj {
174938fd1498Szrj   rtx_insn *insn;
175038fd1498Szrj   rtx note = note_or_insn;
175138fd1498Szrj 
175238fd1498Szrj   if (INSN_P (note_or_insn))
175338fd1498Szrj     {
175438fd1498Szrj       note = find_reg_note (note_or_insn, REG_EH_REGION, NULL_RTX);
175538fd1498Szrj       if (note == NULL)
175638fd1498Szrj 	return;
175738fd1498Szrj     }
1758*58e805e6Szrj   else if (is_a <rtx_insn *> (note_or_insn))
1759*58e805e6Szrj     return;
176038fd1498Szrj   note = XEXP (note, 0);
176138fd1498Szrj 
176238fd1498Szrj   for (insn = first; insn != last ; insn = NEXT_INSN (insn))
176338fd1498Szrj     if (!find_reg_note (insn, REG_EH_REGION, NULL_RTX)
176438fd1498Szrj         && insn_could_throw_p (insn))
176538fd1498Szrj       add_reg_note (insn, REG_EH_REGION, note);
176638fd1498Szrj }
176738fd1498Szrj 
176838fd1498Szrj /* Likewise, but iterate backward.  */
176938fd1498Szrj 
177038fd1498Szrj void
copy_reg_eh_region_note_backward(rtx note_or_insn,rtx_insn * last,rtx first)177138fd1498Szrj copy_reg_eh_region_note_backward (rtx note_or_insn, rtx_insn *last, rtx first)
177238fd1498Szrj {
177338fd1498Szrj   rtx_insn *insn;
177438fd1498Szrj   rtx note = note_or_insn;
177538fd1498Szrj 
177638fd1498Szrj   if (INSN_P (note_or_insn))
177738fd1498Szrj     {
177838fd1498Szrj       note = find_reg_note (note_or_insn, REG_EH_REGION, NULL_RTX);
177938fd1498Szrj       if (note == NULL)
178038fd1498Szrj 	return;
178138fd1498Szrj     }
1782*58e805e6Szrj   else if (is_a <rtx_insn *> (note_or_insn))
1783*58e805e6Szrj     return;
178438fd1498Szrj   note = XEXP (note, 0);
178538fd1498Szrj 
178638fd1498Szrj   for (insn = last; insn != first; insn = PREV_INSN (insn))
178738fd1498Szrj     if (insn_could_throw_p (insn))
178838fd1498Szrj       add_reg_note (insn, REG_EH_REGION, note);
178938fd1498Szrj }
179038fd1498Szrj 
179138fd1498Szrj 
179238fd1498Szrj /* Extract all EH information from INSN.  Return true if the insn
179338fd1498Szrj    was marked NOTHROW.  */
179438fd1498Szrj 
179538fd1498Szrj static bool
get_eh_region_and_lp_from_rtx(const_rtx insn,eh_region * pr,eh_landing_pad * plp)179638fd1498Szrj get_eh_region_and_lp_from_rtx (const_rtx insn, eh_region *pr,
179738fd1498Szrj 			       eh_landing_pad *plp)
179838fd1498Szrj {
179938fd1498Szrj   eh_landing_pad lp = NULL;
180038fd1498Szrj   eh_region r = NULL;
180138fd1498Szrj   bool ret = false;
180238fd1498Szrj   rtx note;
180338fd1498Szrj   int lp_nr;
180438fd1498Szrj 
180538fd1498Szrj   if (! INSN_P (insn))
180638fd1498Szrj     goto egress;
180738fd1498Szrj 
180838fd1498Szrj   if (NONJUMP_INSN_P (insn)
180938fd1498Szrj       && GET_CODE (PATTERN (insn)) == SEQUENCE)
181038fd1498Szrj     insn = XVECEXP (PATTERN (insn), 0, 0);
181138fd1498Szrj 
181238fd1498Szrj   note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
181338fd1498Szrj   if (!note)
181438fd1498Szrj     {
181538fd1498Szrj       ret = !insn_could_throw_p (insn);
181638fd1498Szrj       goto egress;
181738fd1498Szrj     }
181838fd1498Szrj 
181938fd1498Szrj   lp_nr = INTVAL (XEXP (note, 0));
182038fd1498Szrj   if (lp_nr == 0 || lp_nr == INT_MIN)
182138fd1498Szrj     {
182238fd1498Szrj       ret = true;
182338fd1498Szrj       goto egress;
182438fd1498Szrj     }
182538fd1498Szrj 
182638fd1498Szrj   if (lp_nr < 0)
182738fd1498Szrj     r = (*cfun->eh->region_array)[-lp_nr];
182838fd1498Szrj   else
182938fd1498Szrj     {
183038fd1498Szrj       lp = (*cfun->eh->lp_array)[lp_nr];
183138fd1498Szrj       r = lp->region;
183238fd1498Szrj     }
183338fd1498Szrj 
183438fd1498Szrj  egress:
183538fd1498Szrj   *plp = lp;
183638fd1498Szrj   *pr = r;
183738fd1498Szrj   return ret;
183838fd1498Szrj }
183938fd1498Szrj 
184038fd1498Szrj /* Return the landing pad to which INSN may go, or NULL if it does not
184138fd1498Szrj    have a reachable landing pad within this function.  */
184238fd1498Szrj 
184338fd1498Szrj eh_landing_pad
get_eh_landing_pad_from_rtx(const_rtx insn)184438fd1498Szrj get_eh_landing_pad_from_rtx (const_rtx insn)
184538fd1498Szrj {
184638fd1498Szrj   eh_landing_pad lp;
184738fd1498Szrj   eh_region r;
184838fd1498Szrj 
184938fd1498Szrj   get_eh_region_and_lp_from_rtx (insn, &r, &lp);
185038fd1498Szrj   return lp;
185138fd1498Szrj }
185238fd1498Szrj 
185338fd1498Szrj /* Return the region to which INSN may go, or NULL if it does not
185438fd1498Szrj    have a reachable region within this function.  */
185538fd1498Szrj 
185638fd1498Szrj eh_region
get_eh_region_from_rtx(const_rtx insn)185738fd1498Szrj get_eh_region_from_rtx (const_rtx insn)
185838fd1498Szrj {
185938fd1498Szrj   eh_landing_pad lp;
186038fd1498Szrj   eh_region r;
186138fd1498Szrj 
186238fd1498Szrj   get_eh_region_and_lp_from_rtx (insn, &r, &lp);
186338fd1498Szrj   return r;
186438fd1498Szrj }
186538fd1498Szrj 
186638fd1498Szrj /* Return true if INSN throws and is caught by something in this function.  */
186738fd1498Szrj 
186838fd1498Szrj bool
can_throw_internal(const_rtx insn)186938fd1498Szrj can_throw_internal (const_rtx insn)
187038fd1498Szrj {
187138fd1498Szrj   return get_eh_landing_pad_from_rtx (insn) != NULL;
187238fd1498Szrj }
187338fd1498Szrj 
187438fd1498Szrj /* Return true if INSN throws and escapes from the current function.  */
187538fd1498Szrj 
187638fd1498Szrj bool
can_throw_external(const_rtx insn)187738fd1498Szrj can_throw_external (const_rtx insn)
187838fd1498Szrj {
187938fd1498Szrj   eh_landing_pad lp;
188038fd1498Szrj   eh_region r;
188138fd1498Szrj   bool nothrow;
188238fd1498Szrj 
188338fd1498Szrj   if (! INSN_P (insn))
188438fd1498Szrj     return false;
188538fd1498Szrj 
188638fd1498Szrj   if (NONJUMP_INSN_P (insn)
188738fd1498Szrj       && GET_CODE (PATTERN (insn)) == SEQUENCE)
188838fd1498Szrj     {
188938fd1498Szrj       rtx_sequence *seq = as_a <rtx_sequence *> (PATTERN (insn));
189038fd1498Szrj       int i, n = seq->len ();
189138fd1498Szrj 
189238fd1498Szrj       for (i = 0; i < n; i++)
189338fd1498Szrj 	if (can_throw_external (seq->element (i)))
189438fd1498Szrj 	  return true;
189538fd1498Szrj 
189638fd1498Szrj       return false;
189738fd1498Szrj     }
189838fd1498Szrj 
189938fd1498Szrj   nothrow = get_eh_region_and_lp_from_rtx (insn, &r, &lp);
190038fd1498Szrj 
190138fd1498Szrj   /* If we can't throw, we obviously can't throw external.  */
190238fd1498Szrj   if (nothrow)
190338fd1498Szrj     return false;
190438fd1498Szrj 
190538fd1498Szrj   /* If we have an internal landing pad, then we're not external.  */
190638fd1498Szrj   if (lp != NULL)
190738fd1498Szrj     return false;
190838fd1498Szrj 
190938fd1498Szrj   /* If we're not within an EH region, then we are external.  */
191038fd1498Szrj   if (r == NULL)
191138fd1498Szrj     return true;
191238fd1498Szrj 
191338fd1498Szrj   /* The only thing that ought to be left is MUST_NOT_THROW regions,
191438fd1498Szrj      which don't always have landing pads.  */
191538fd1498Szrj   gcc_assert (r->type == ERT_MUST_NOT_THROW);
191638fd1498Szrj   return false;
191738fd1498Szrj }
191838fd1498Szrj 
191938fd1498Szrj /* Return true if INSN cannot throw at all.  */
192038fd1498Szrj 
192138fd1498Szrj bool
insn_nothrow_p(const_rtx insn)192238fd1498Szrj insn_nothrow_p (const_rtx insn)
192338fd1498Szrj {
192438fd1498Szrj   eh_landing_pad lp;
192538fd1498Szrj   eh_region r;
192638fd1498Szrj 
192738fd1498Szrj   if (! INSN_P (insn))
192838fd1498Szrj     return true;
192938fd1498Szrj 
193038fd1498Szrj   if (NONJUMP_INSN_P (insn)
193138fd1498Szrj       && GET_CODE (PATTERN (insn)) == SEQUENCE)
193238fd1498Szrj     {
193338fd1498Szrj       rtx_sequence *seq = as_a <rtx_sequence *> (PATTERN (insn));
193438fd1498Szrj       int i, n = seq->len ();
193538fd1498Szrj 
193638fd1498Szrj       for (i = 0; i < n; i++)
193738fd1498Szrj 	if (!insn_nothrow_p (seq->element (i)))
193838fd1498Szrj 	  return false;
193938fd1498Szrj 
194038fd1498Szrj       return true;
194138fd1498Szrj     }
194238fd1498Szrj 
194338fd1498Szrj   return get_eh_region_and_lp_from_rtx (insn, &r, &lp);
194438fd1498Szrj }
194538fd1498Szrj 
194638fd1498Szrj /* Return true if INSN can perform a non-local goto.  */
194738fd1498Szrj /* ??? This test is here in this file because it (ab)uses REG_EH_REGION.  */
194838fd1498Szrj 
194938fd1498Szrj bool
can_nonlocal_goto(const rtx_insn * insn)195038fd1498Szrj can_nonlocal_goto (const rtx_insn *insn)
195138fd1498Szrj {
195238fd1498Szrj   if (nonlocal_goto_handler_labels && CALL_P (insn))
195338fd1498Szrj     {
195438fd1498Szrj       rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
195538fd1498Szrj       if (!note || INTVAL (XEXP (note, 0)) != INT_MIN)
195638fd1498Szrj 	return true;
195738fd1498Szrj     }
195838fd1498Szrj   return false;
195938fd1498Szrj }
196038fd1498Szrj 
196138fd1498Szrj /* Set TREE_NOTHROW and crtl->all_throwers_are_sibcalls.  */
196238fd1498Szrj 
196338fd1498Szrj static unsigned int
set_nothrow_function_flags(void)196438fd1498Szrj set_nothrow_function_flags (void)
196538fd1498Szrj {
196638fd1498Szrj   rtx_insn *insn;
196738fd1498Szrj 
196838fd1498Szrj   crtl->nothrow = 1;
196938fd1498Szrj 
197038fd1498Szrj   /* Assume crtl->all_throwers_are_sibcalls until we encounter
197138fd1498Szrj      something that can throw an exception.  We specifically exempt
197238fd1498Szrj      CALL_INSNs that are SIBLING_CALL_P, as these are really jumps,
197338fd1498Szrj      and can't throw.  Most CALL_INSNs are not SIBLING_CALL_P, so this
197438fd1498Szrj      is optimistic.  */
197538fd1498Szrj 
197638fd1498Szrj   crtl->all_throwers_are_sibcalls = 1;
197738fd1498Szrj 
197838fd1498Szrj   /* If we don't know that this implementation of the function will
197938fd1498Szrj      actually be used, then we must not set TREE_NOTHROW, since
198038fd1498Szrj      callers must not assume that this function does not throw.  */
198138fd1498Szrj   if (TREE_NOTHROW (current_function_decl))
198238fd1498Szrj     return 0;
198338fd1498Szrj 
198438fd1498Szrj   if (! flag_exceptions)
198538fd1498Szrj     return 0;
198638fd1498Szrj 
198738fd1498Szrj   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
198838fd1498Szrj     if (can_throw_external (insn))
198938fd1498Szrj       {
199038fd1498Szrj         crtl->nothrow = 0;
199138fd1498Szrj 
199238fd1498Szrj 	if (!CALL_P (insn) || !SIBLING_CALL_P (insn))
199338fd1498Szrj 	  {
199438fd1498Szrj 	    crtl->all_throwers_are_sibcalls = 0;
199538fd1498Szrj 	    return 0;
199638fd1498Szrj 	  }
199738fd1498Szrj       }
199838fd1498Szrj 
199938fd1498Szrj   if (crtl->nothrow
200038fd1498Szrj       && (cgraph_node::get (current_function_decl)->get_availability ()
200138fd1498Szrj           >= AVAIL_AVAILABLE))
200238fd1498Szrj     {
200338fd1498Szrj       struct cgraph_node *node = cgraph_node::get (current_function_decl);
200438fd1498Szrj       struct cgraph_edge *e;
200538fd1498Szrj       for (e = node->callers; e; e = e->next_caller)
200638fd1498Szrj         e->can_throw_external = false;
200738fd1498Szrj       node->set_nothrow_flag (true);
200838fd1498Szrj 
200938fd1498Szrj       if (dump_file)
201038fd1498Szrj 	fprintf (dump_file, "Marking function nothrow: %s\n\n",
201138fd1498Szrj 		 current_function_name ());
201238fd1498Szrj     }
201338fd1498Szrj   return 0;
201438fd1498Szrj }
201538fd1498Szrj 
201638fd1498Szrj namespace {
201738fd1498Szrj 
201838fd1498Szrj const pass_data pass_data_set_nothrow_function_flags =
201938fd1498Szrj {
202038fd1498Szrj   RTL_PASS, /* type */
202138fd1498Szrj   "nothrow", /* name */
202238fd1498Szrj   OPTGROUP_NONE, /* optinfo_flags */
202338fd1498Szrj   TV_NONE, /* tv_id */
202438fd1498Szrj   0, /* properties_required */
202538fd1498Szrj   0, /* properties_provided */
202638fd1498Szrj   0, /* properties_destroyed */
202738fd1498Szrj   0, /* todo_flags_start */
202838fd1498Szrj   0, /* todo_flags_finish */
202938fd1498Szrj };
203038fd1498Szrj 
203138fd1498Szrj class pass_set_nothrow_function_flags : public rtl_opt_pass
203238fd1498Szrj {
203338fd1498Szrj public:
pass_set_nothrow_function_flags(gcc::context * ctxt)203438fd1498Szrj   pass_set_nothrow_function_flags (gcc::context *ctxt)
203538fd1498Szrj     : rtl_opt_pass (pass_data_set_nothrow_function_flags, ctxt)
203638fd1498Szrj   {}
203738fd1498Szrj 
203838fd1498Szrj   /* opt_pass methods: */
execute(function *)203938fd1498Szrj   virtual unsigned int execute (function *)
204038fd1498Szrj     {
204138fd1498Szrj       return set_nothrow_function_flags ();
204238fd1498Szrj     }
204338fd1498Szrj 
204438fd1498Szrj }; // class pass_set_nothrow_function_flags
204538fd1498Szrj 
204638fd1498Szrj } // anon namespace
204738fd1498Szrj 
204838fd1498Szrj rtl_opt_pass *
make_pass_set_nothrow_function_flags(gcc::context * ctxt)204938fd1498Szrj make_pass_set_nothrow_function_flags (gcc::context *ctxt)
205038fd1498Szrj {
205138fd1498Szrj   return new pass_set_nothrow_function_flags (ctxt);
205238fd1498Szrj }
205338fd1498Szrj 
205438fd1498Szrj 
205538fd1498Szrj /* Various hooks for unwind library.  */
205638fd1498Szrj 
205738fd1498Szrj /* Expand the EH support builtin functions:
205838fd1498Szrj    __builtin_eh_pointer and __builtin_eh_filter.  */
205938fd1498Szrj 
206038fd1498Szrj static eh_region
expand_builtin_eh_common(tree region_nr_t)206138fd1498Szrj expand_builtin_eh_common (tree region_nr_t)
206238fd1498Szrj {
206338fd1498Szrj   HOST_WIDE_INT region_nr;
206438fd1498Szrj   eh_region region;
206538fd1498Szrj 
206638fd1498Szrj   gcc_assert (tree_fits_shwi_p (region_nr_t));
206738fd1498Szrj   region_nr = tree_to_shwi (region_nr_t);
206838fd1498Szrj 
206938fd1498Szrj   region = (*cfun->eh->region_array)[region_nr];
207038fd1498Szrj 
207138fd1498Szrj   /* ??? We shouldn't have been able to delete a eh region without
207238fd1498Szrj      deleting all the code that depended on it.  */
207338fd1498Szrj   gcc_assert (region != NULL);
207438fd1498Szrj 
207538fd1498Szrj   return region;
207638fd1498Szrj }
207738fd1498Szrj 
207838fd1498Szrj /* Expand to the exc_ptr value from the given eh region.  */
207938fd1498Szrj 
208038fd1498Szrj rtx
expand_builtin_eh_pointer(tree exp)208138fd1498Szrj expand_builtin_eh_pointer (tree exp)
208238fd1498Szrj {
208338fd1498Szrj   eh_region region
208438fd1498Szrj     = expand_builtin_eh_common (CALL_EXPR_ARG (exp, 0));
208538fd1498Szrj   if (region->exc_ptr_reg == NULL)
208638fd1498Szrj     region->exc_ptr_reg = gen_reg_rtx (ptr_mode);
208738fd1498Szrj   return region->exc_ptr_reg;
208838fd1498Szrj }
208938fd1498Szrj 
209038fd1498Szrj /* Expand to the filter value from the given eh region.  */
209138fd1498Szrj 
209238fd1498Szrj rtx
expand_builtin_eh_filter(tree exp)209338fd1498Szrj expand_builtin_eh_filter (tree exp)
209438fd1498Szrj {
209538fd1498Szrj   eh_region region
209638fd1498Szrj     = expand_builtin_eh_common (CALL_EXPR_ARG (exp, 0));
209738fd1498Szrj   if (region->filter_reg == NULL)
209838fd1498Szrj     region->filter_reg = gen_reg_rtx (targetm.eh_return_filter_mode ());
209938fd1498Szrj   return region->filter_reg;
210038fd1498Szrj }
210138fd1498Szrj 
210238fd1498Szrj /* Copy the exc_ptr and filter values from one landing pad's registers
210338fd1498Szrj    to another.  This is used to inline the resx statement.  */
210438fd1498Szrj 
210538fd1498Szrj rtx
expand_builtin_eh_copy_values(tree exp)210638fd1498Szrj expand_builtin_eh_copy_values (tree exp)
210738fd1498Szrj {
210838fd1498Szrj   eh_region dst
210938fd1498Szrj     = expand_builtin_eh_common (CALL_EXPR_ARG (exp, 0));
211038fd1498Szrj   eh_region src
211138fd1498Szrj     = expand_builtin_eh_common (CALL_EXPR_ARG (exp, 1));
211238fd1498Szrj   scalar_int_mode fmode = targetm.eh_return_filter_mode ();
211338fd1498Szrj 
211438fd1498Szrj   if (dst->exc_ptr_reg == NULL)
211538fd1498Szrj     dst->exc_ptr_reg = gen_reg_rtx (ptr_mode);
211638fd1498Szrj   if (src->exc_ptr_reg == NULL)
211738fd1498Szrj     src->exc_ptr_reg = gen_reg_rtx (ptr_mode);
211838fd1498Szrj 
211938fd1498Szrj   if (dst->filter_reg == NULL)
212038fd1498Szrj     dst->filter_reg = gen_reg_rtx (fmode);
212138fd1498Szrj   if (src->filter_reg == NULL)
212238fd1498Szrj     src->filter_reg = gen_reg_rtx (fmode);
212338fd1498Szrj 
212438fd1498Szrj   emit_move_insn (dst->exc_ptr_reg, src->exc_ptr_reg);
212538fd1498Szrj   emit_move_insn (dst->filter_reg, src->filter_reg);
212638fd1498Szrj 
212738fd1498Szrj   return const0_rtx;
212838fd1498Szrj }
212938fd1498Szrj 
213038fd1498Szrj /* Do any necessary initialization to access arbitrary stack frames.
213138fd1498Szrj    On the SPARC, this means flushing the register windows.  */
213238fd1498Szrj 
213338fd1498Szrj void
expand_builtin_unwind_init(void)213438fd1498Szrj expand_builtin_unwind_init (void)
213538fd1498Szrj {
213638fd1498Szrj   /* Set this so all the registers get saved in our frame; we need to be
213738fd1498Szrj      able to copy the saved values for any registers from frames we unwind.  */
213838fd1498Szrj   crtl->saves_all_registers = 1;
213938fd1498Szrj 
214038fd1498Szrj   SETUP_FRAME_ADDRESSES ();
214138fd1498Szrj }
214238fd1498Szrj 
214338fd1498Szrj /* Map a non-negative number to an eh return data register number; expands
214438fd1498Szrj    to -1 if no return data register is associated with the input number.
214538fd1498Szrj    At least the inputs 0 and 1 must be mapped; the target may provide more.  */
214638fd1498Szrj 
214738fd1498Szrj rtx
expand_builtin_eh_return_data_regno(tree exp)214838fd1498Szrj expand_builtin_eh_return_data_regno (tree exp)
214938fd1498Szrj {
215038fd1498Szrj   tree which = CALL_EXPR_ARG (exp, 0);
215138fd1498Szrj   unsigned HOST_WIDE_INT iwhich;
215238fd1498Szrj 
215338fd1498Szrj   if (TREE_CODE (which) != INTEGER_CST)
215438fd1498Szrj     {
215538fd1498Szrj       error ("argument of %<__builtin_eh_return_regno%> must be constant");
215638fd1498Szrj       return constm1_rtx;
215738fd1498Szrj     }
215838fd1498Szrj 
215938fd1498Szrj   iwhich = tree_to_uhwi (which);
216038fd1498Szrj   iwhich = EH_RETURN_DATA_REGNO (iwhich);
216138fd1498Szrj   if (iwhich == INVALID_REGNUM)
216238fd1498Szrj     return constm1_rtx;
216338fd1498Szrj 
216438fd1498Szrj #ifdef DWARF_FRAME_REGNUM
216538fd1498Szrj   iwhich = DWARF_FRAME_REGNUM (iwhich);
216638fd1498Szrj #else
216738fd1498Szrj   iwhich = DBX_REGISTER_NUMBER (iwhich);
216838fd1498Szrj #endif
216938fd1498Szrj 
217038fd1498Szrj   return GEN_INT (iwhich);
217138fd1498Szrj }
217238fd1498Szrj 
217338fd1498Szrj /* Given a value extracted from the return address register or stack slot,
217438fd1498Szrj    return the actual address encoded in that value.  */
217538fd1498Szrj 
217638fd1498Szrj rtx
expand_builtin_extract_return_addr(tree addr_tree)217738fd1498Szrj expand_builtin_extract_return_addr (tree addr_tree)
217838fd1498Szrj {
217938fd1498Szrj   rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
218038fd1498Szrj 
218138fd1498Szrj   if (GET_MODE (addr) != Pmode
218238fd1498Szrj       && GET_MODE (addr) != VOIDmode)
218338fd1498Szrj     {
218438fd1498Szrj #ifdef POINTERS_EXTEND_UNSIGNED
218538fd1498Szrj       addr = convert_memory_address (Pmode, addr);
218638fd1498Szrj #else
218738fd1498Szrj       addr = convert_to_mode (Pmode, addr, 0);
218838fd1498Szrj #endif
218938fd1498Szrj     }
219038fd1498Szrj 
219138fd1498Szrj   /* First mask out any unwanted bits.  */
219238fd1498Szrj   rtx mask = MASK_RETURN_ADDR;
219338fd1498Szrj   if (mask)
219438fd1498Szrj     expand_and (Pmode, addr, mask, addr);
219538fd1498Szrj 
219638fd1498Szrj   /* Then adjust to find the real return address.  */
219738fd1498Szrj   if (RETURN_ADDR_OFFSET)
219838fd1498Szrj     addr = plus_constant (Pmode, addr, RETURN_ADDR_OFFSET);
219938fd1498Szrj 
220038fd1498Szrj   return addr;
220138fd1498Szrj }
220238fd1498Szrj 
220338fd1498Szrj /* Given an actual address in addr_tree, do any necessary encoding
220438fd1498Szrj    and return the value to be stored in the return address register or
220538fd1498Szrj    stack slot so the epilogue will return to that address.  */
220638fd1498Szrj 
220738fd1498Szrj rtx
expand_builtin_frob_return_addr(tree addr_tree)220838fd1498Szrj expand_builtin_frob_return_addr (tree addr_tree)
220938fd1498Szrj {
221038fd1498Szrj   rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, EXPAND_NORMAL);
221138fd1498Szrj 
221238fd1498Szrj   addr = convert_memory_address (Pmode, addr);
221338fd1498Szrj 
221438fd1498Szrj   if (RETURN_ADDR_OFFSET)
221538fd1498Szrj     {
221638fd1498Szrj       addr = force_reg (Pmode, addr);
221738fd1498Szrj       addr = plus_constant (Pmode, addr, -RETURN_ADDR_OFFSET);
221838fd1498Szrj     }
221938fd1498Szrj 
222038fd1498Szrj   return addr;
222138fd1498Szrj }
222238fd1498Szrj 
222338fd1498Szrj /* Set up the epilogue with the magic bits we'll need to return to the
222438fd1498Szrj    exception handler.  */
222538fd1498Szrj 
222638fd1498Szrj void
expand_builtin_eh_return(tree stackadj_tree ATTRIBUTE_UNUSED,tree handler_tree)222738fd1498Szrj expand_builtin_eh_return (tree stackadj_tree ATTRIBUTE_UNUSED,
222838fd1498Szrj 			  tree handler_tree)
222938fd1498Szrj {
223038fd1498Szrj   rtx tmp;
223138fd1498Szrj 
223238fd1498Szrj #ifdef EH_RETURN_STACKADJ_RTX
223338fd1498Szrj   tmp = expand_expr (stackadj_tree, crtl->eh.ehr_stackadj,
223438fd1498Szrj 		     VOIDmode, EXPAND_NORMAL);
223538fd1498Szrj   tmp = convert_memory_address (Pmode, tmp);
223638fd1498Szrj   if (!crtl->eh.ehr_stackadj)
223738fd1498Szrj     crtl->eh.ehr_stackadj = copy_addr_to_reg (tmp);
223838fd1498Szrj   else if (tmp != crtl->eh.ehr_stackadj)
223938fd1498Szrj     emit_move_insn (crtl->eh.ehr_stackadj, tmp);
224038fd1498Szrj #endif
224138fd1498Szrj 
224238fd1498Szrj   tmp = expand_expr (handler_tree, crtl->eh.ehr_handler,
224338fd1498Szrj 		     VOIDmode, EXPAND_NORMAL);
224438fd1498Szrj   tmp = convert_memory_address (Pmode, tmp);
224538fd1498Szrj   if (!crtl->eh.ehr_handler)
224638fd1498Szrj     crtl->eh.ehr_handler = copy_addr_to_reg (tmp);
224738fd1498Szrj   else if (tmp != crtl->eh.ehr_handler)
224838fd1498Szrj     emit_move_insn (crtl->eh.ehr_handler, tmp);
224938fd1498Szrj 
225038fd1498Szrj   if (!crtl->eh.ehr_label)
225138fd1498Szrj     crtl->eh.ehr_label = gen_label_rtx ();
225238fd1498Szrj   emit_jump (crtl->eh.ehr_label);
225338fd1498Szrj }
225438fd1498Szrj 
225538fd1498Szrj /* Expand __builtin_eh_return.  This exit path from the function loads up
225638fd1498Szrj    the eh return data registers, adjusts the stack, and branches to a
225738fd1498Szrj    given PC other than the normal return address.  */
225838fd1498Szrj 
225938fd1498Szrj void
expand_eh_return(void)226038fd1498Szrj expand_eh_return (void)
226138fd1498Szrj {
226238fd1498Szrj   rtx_code_label *around_label;
226338fd1498Szrj 
226438fd1498Szrj   if (! crtl->eh.ehr_label)
226538fd1498Szrj     return;
226638fd1498Szrj 
226738fd1498Szrj   crtl->calls_eh_return = 1;
226838fd1498Szrj 
226938fd1498Szrj #ifdef EH_RETURN_STACKADJ_RTX
227038fd1498Szrj   emit_move_insn (EH_RETURN_STACKADJ_RTX, const0_rtx);
227138fd1498Szrj #endif
227238fd1498Szrj 
227338fd1498Szrj   around_label = gen_label_rtx ();
227438fd1498Szrj   emit_jump (around_label);
227538fd1498Szrj 
227638fd1498Szrj   emit_label (crtl->eh.ehr_label);
227738fd1498Szrj   clobber_return_register ();
227838fd1498Szrj 
227938fd1498Szrj #ifdef EH_RETURN_STACKADJ_RTX
228038fd1498Szrj   emit_move_insn (EH_RETURN_STACKADJ_RTX, crtl->eh.ehr_stackadj);
228138fd1498Szrj #endif
228238fd1498Szrj 
228338fd1498Szrj   if (targetm.have_eh_return ())
228438fd1498Szrj     emit_insn (targetm.gen_eh_return (crtl->eh.ehr_handler));
228538fd1498Szrj   else
228638fd1498Szrj     {
228738fd1498Szrj       if (rtx handler = EH_RETURN_HANDLER_RTX)
228838fd1498Szrj 	emit_move_insn (handler, crtl->eh.ehr_handler);
228938fd1498Szrj       else
229038fd1498Szrj 	error ("__builtin_eh_return not supported on this target");
229138fd1498Szrj     }
229238fd1498Szrj 
229338fd1498Szrj   emit_label (around_label);
229438fd1498Szrj }
229538fd1498Szrj 
229638fd1498Szrj /* Convert a ptr_mode address ADDR_TREE to a Pmode address controlled by
229738fd1498Szrj    POINTERS_EXTEND_UNSIGNED and return it.  */
229838fd1498Szrj 
229938fd1498Szrj rtx
expand_builtin_extend_pointer(tree addr_tree)230038fd1498Szrj expand_builtin_extend_pointer (tree addr_tree)
230138fd1498Szrj {
230238fd1498Szrj   rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, EXPAND_NORMAL);
230338fd1498Szrj   int extend;
230438fd1498Szrj 
230538fd1498Szrj #ifdef POINTERS_EXTEND_UNSIGNED
230638fd1498Szrj   extend = POINTERS_EXTEND_UNSIGNED;
230738fd1498Szrj #else
230838fd1498Szrj   /* The previous EH code did an unsigned extend by default, so we do this also
230938fd1498Szrj      for consistency.  */
231038fd1498Szrj   extend = 1;
231138fd1498Szrj #endif
231238fd1498Szrj 
231338fd1498Szrj   return convert_modes (targetm.unwind_word_mode (), ptr_mode, addr, extend);
231438fd1498Szrj }
231538fd1498Szrj 
231638fd1498Szrj static int
add_action_record(action_hash_type * ar_hash,int filter,int next)231738fd1498Szrj add_action_record (action_hash_type *ar_hash, int filter, int next)
231838fd1498Szrj {
231938fd1498Szrj   struct action_record **slot, *new_ar, tmp;
232038fd1498Szrj 
232138fd1498Szrj   tmp.filter = filter;
232238fd1498Szrj   tmp.next = next;
232338fd1498Szrj   slot = ar_hash->find_slot (&tmp, INSERT);
232438fd1498Szrj 
232538fd1498Szrj   if ((new_ar = *slot) == NULL)
232638fd1498Szrj     {
232738fd1498Szrj       new_ar = XNEW (struct action_record);
232838fd1498Szrj       new_ar->offset = crtl->eh.action_record_data->length () + 1;
232938fd1498Szrj       new_ar->filter = filter;
233038fd1498Szrj       new_ar->next = next;
233138fd1498Szrj       *slot = new_ar;
233238fd1498Szrj 
233338fd1498Szrj       /* The filter value goes in untouched.  The link to the next
233438fd1498Szrj 	 record is a "self-relative" byte offset, or zero to indicate
233538fd1498Szrj 	 that there is no next record.  So convert the absolute 1 based
233638fd1498Szrj 	 indices we've been carrying around into a displacement.  */
233738fd1498Szrj 
233838fd1498Szrj       push_sleb128 (&crtl->eh.action_record_data, filter);
233938fd1498Szrj       if (next)
234038fd1498Szrj 	next -= crtl->eh.action_record_data->length () + 1;
234138fd1498Szrj       push_sleb128 (&crtl->eh.action_record_data, next);
234238fd1498Szrj     }
234338fd1498Szrj 
234438fd1498Szrj   return new_ar->offset;
234538fd1498Szrj }
234638fd1498Szrj 
234738fd1498Szrj static int
collect_one_action_chain(action_hash_type * ar_hash,eh_region region)234838fd1498Szrj collect_one_action_chain (action_hash_type *ar_hash, eh_region region)
234938fd1498Szrj {
235038fd1498Szrj   int next;
235138fd1498Szrj 
235238fd1498Szrj   /* If we've reached the top of the region chain, then we have
235338fd1498Szrj      no actions, and require no landing pad.  */
235438fd1498Szrj   if (region == NULL)
235538fd1498Szrj     return -1;
235638fd1498Szrj 
235738fd1498Szrj   switch (region->type)
235838fd1498Szrj     {
235938fd1498Szrj     case ERT_CLEANUP:
236038fd1498Szrj       {
236138fd1498Szrj 	eh_region r;
236238fd1498Szrj 	/* A cleanup adds a zero filter to the beginning of the chain, but
236338fd1498Szrj 	   there are special cases to look out for.  If there are *only*
236438fd1498Szrj 	   cleanups along a path, then it compresses to a zero action.
236538fd1498Szrj 	   Further, if there are multiple cleanups along a path, we only
236638fd1498Szrj 	   need to represent one of them, as that is enough to trigger
236738fd1498Szrj 	   entry to the landing pad at runtime.  */
236838fd1498Szrj 	next = collect_one_action_chain (ar_hash, region->outer);
236938fd1498Szrj 	if (next <= 0)
237038fd1498Szrj 	  return 0;
237138fd1498Szrj 	for (r = region->outer; r ; r = r->outer)
237238fd1498Szrj 	  if (r->type == ERT_CLEANUP)
237338fd1498Szrj 	    return next;
237438fd1498Szrj 	return add_action_record (ar_hash, 0, next);
237538fd1498Szrj       }
237638fd1498Szrj 
237738fd1498Szrj     case ERT_TRY:
237838fd1498Szrj       {
237938fd1498Szrj 	eh_catch c;
238038fd1498Szrj 
238138fd1498Szrj 	/* Process the associated catch regions in reverse order.
238238fd1498Szrj 	   If there's a catch-all handler, then we don't need to
238338fd1498Szrj 	   search outer regions.  Use a magic -3 value to record
238438fd1498Szrj 	   that we haven't done the outer search.  */
238538fd1498Szrj 	next = -3;
238638fd1498Szrj 	for (c = region->u.eh_try.last_catch; c ; c = c->prev_catch)
238738fd1498Szrj 	  {
238838fd1498Szrj 	    if (c->type_list == NULL)
238938fd1498Szrj 	      {
239038fd1498Szrj 		/* Retrieve the filter from the head of the filter list
239138fd1498Szrj 		   where we have stored it (see assign_filter_values).  */
239238fd1498Szrj 		int filter = TREE_INT_CST_LOW (TREE_VALUE (c->filter_list));
239338fd1498Szrj 		next = add_action_record (ar_hash, filter, 0);
239438fd1498Szrj 	      }
239538fd1498Szrj 	    else
239638fd1498Szrj 	      {
239738fd1498Szrj 		/* Once the outer search is done, trigger an action record for
239838fd1498Szrj 		   each filter we have.  */
239938fd1498Szrj 		tree flt_node;
240038fd1498Szrj 
240138fd1498Szrj 		if (next == -3)
240238fd1498Szrj 		  {
240338fd1498Szrj 		    next = collect_one_action_chain (ar_hash, region->outer);
240438fd1498Szrj 
240538fd1498Szrj 		    /* If there is no next action, terminate the chain.  */
240638fd1498Szrj 		    if (next == -1)
240738fd1498Szrj 		      next = 0;
240838fd1498Szrj 		    /* If all outer actions are cleanups or must_not_throw,
240938fd1498Szrj 		       we'll have no action record for it, since we had wanted
241038fd1498Szrj 		       to encode these states in the call-site record directly.
241138fd1498Szrj 		       Add a cleanup action to the chain to catch these.  */
241238fd1498Szrj 		    else if (next <= 0)
241338fd1498Szrj 		      next = add_action_record (ar_hash, 0, 0);
241438fd1498Szrj 		  }
241538fd1498Szrj 
241638fd1498Szrj 		flt_node = c->filter_list;
241738fd1498Szrj 		for (; flt_node; flt_node = TREE_CHAIN (flt_node))
241838fd1498Szrj 		  {
241938fd1498Szrj 		    int filter = TREE_INT_CST_LOW (TREE_VALUE (flt_node));
242038fd1498Szrj 		    next = add_action_record (ar_hash, filter, next);
242138fd1498Szrj 		  }
242238fd1498Szrj 	      }
242338fd1498Szrj 	  }
242438fd1498Szrj 	return next;
242538fd1498Szrj       }
242638fd1498Szrj 
242738fd1498Szrj     case ERT_ALLOWED_EXCEPTIONS:
242838fd1498Szrj       /* An exception specification adds its filter to the
242938fd1498Szrj 	 beginning of the chain.  */
243038fd1498Szrj       next = collect_one_action_chain (ar_hash, region->outer);
243138fd1498Szrj 
243238fd1498Szrj       /* If there is no next action, terminate the chain.  */
243338fd1498Szrj       if (next == -1)
243438fd1498Szrj 	next = 0;
243538fd1498Szrj       /* If all outer actions are cleanups or must_not_throw,
243638fd1498Szrj 	 we'll have no action record for it, since we had wanted
243738fd1498Szrj 	 to encode these states in the call-site record directly.
243838fd1498Szrj 	 Add a cleanup action to the chain to catch these.  */
243938fd1498Szrj       else if (next <= 0)
244038fd1498Szrj 	next = add_action_record (ar_hash, 0, 0);
244138fd1498Szrj 
244238fd1498Szrj       return add_action_record (ar_hash, region->u.allowed.filter, next);
244338fd1498Szrj 
244438fd1498Szrj     case ERT_MUST_NOT_THROW:
244538fd1498Szrj       /* A must-not-throw region with no inner handlers or cleanups
244638fd1498Szrj 	 requires no call-site entry.  Note that this differs from
244738fd1498Szrj 	 the no handler or cleanup case in that we do require an lsda
244838fd1498Szrj 	 to be generated.  Return a magic -2 value to record this.  */
244938fd1498Szrj       return -2;
245038fd1498Szrj     }
245138fd1498Szrj 
245238fd1498Szrj   gcc_unreachable ();
245338fd1498Szrj }
245438fd1498Szrj 
245538fd1498Szrj static int
add_call_site(rtx landing_pad,int action,int section)245638fd1498Szrj add_call_site (rtx landing_pad, int action, int section)
245738fd1498Szrj {
245838fd1498Szrj   call_site_record record;
245938fd1498Szrj 
246038fd1498Szrj   record = ggc_alloc<call_site_record_d> ();
246138fd1498Szrj   record->landing_pad = landing_pad;
246238fd1498Szrj   record->action = action;
246338fd1498Szrj 
246438fd1498Szrj   vec_safe_push (crtl->eh.call_site_record_v[section], record);
246538fd1498Szrj 
246638fd1498Szrj   return call_site_base + crtl->eh.call_site_record_v[section]->length () - 1;
246738fd1498Szrj }
246838fd1498Szrj 
246938fd1498Szrj static rtx_note *
emit_note_eh_region_end(rtx_insn * insn)247038fd1498Szrj emit_note_eh_region_end (rtx_insn *insn)
247138fd1498Szrj {
247238fd1498Szrj   return emit_note_after (NOTE_INSN_EH_REGION_END, insn);
247338fd1498Szrj }
247438fd1498Szrj 
247538fd1498Szrj /* Add NOP after NOTE_INSN_SWITCH_TEXT_SECTIONS when the cold section starts
247638fd1498Szrj    with landing pad.
247738fd1498Szrj    With landing pad being at offset 0 from the start label of the section
247838fd1498Szrj    we would miss EH delivery because 0 is special and means no landing pad.  */
247938fd1498Szrj 
248038fd1498Szrj static bool
maybe_add_nop_after_section_switch(void)248138fd1498Szrj maybe_add_nop_after_section_switch (void)
248238fd1498Szrj {
248338fd1498Szrj   if (!crtl->uses_eh_lsda
248438fd1498Szrj       || !crtl->eh.call_site_record_v[1])
248538fd1498Szrj     return false;
248638fd1498Szrj   int n = vec_safe_length (crtl->eh.call_site_record_v[1]);
248738fd1498Szrj   hash_set<rtx_insn *> visited;
248838fd1498Szrj 
248938fd1498Szrj   for (int i = 0; i < n; ++i)
249038fd1498Szrj     {
249138fd1498Szrj       struct call_site_record_d *cs
249238fd1498Szrj 	 = (*crtl->eh.call_site_record_v[1])[i];
249338fd1498Szrj       if (cs->landing_pad)
249438fd1498Szrj 	{
249538fd1498Szrj 	  rtx_insn *insn = as_a <rtx_insn *> (cs->landing_pad);
249638fd1498Szrj 	  while (true)
249738fd1498Szrj 	    {
249838fd1498Szrj 	      /* Landing pads have LABEL_PRESERVE_P flag set.  This check make
249938fd1498Szrj 		 sure that we do not walk past landing pad visited earlier
250038fd1498Szrj 		 which would result in possible quadratic behaviour.  */
250138fd1498Szrj 	      if (LABEL_P (insn) && LABEL_PRESERVE_P (insn)
250238fd1498Szrj 		  && visited.add (insn))
250338fd1498Szrj 		break;
250438fd1498Szrj 
250538fd1498Szrj 	      /* Conservatively assume that ASM insn may be empty.  We have
250638fd1498Szrj 		 now way to tell what they contain.  */
250738fd1498Szrj 	      if (active_insn_p (insn)
250838fd1498Szrj 		  && GET_CODE (PATTERN (insn)) != ASM_INPUT
250938fd1498Szrj 		  && GET_CODE (PATTERN (insn)) != ASM_OPERANDS)
251038fd1498Szrj 		break;
251138fd1498Szrj 
251238fd1498Szrj 	      /* If we reached the start of hot section, then NOP will be
251338fd1498Szrj 		 needed.  */
251438fd1498Szrj 	      if (GET_CODE (insn) == NOTE
251538fd1498Szrj 		  && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
251638fd1498Szrj 		{
251738fd1498Szrj 		  emit_insn_after (gen_nop (), insn);
251838fd1498Szrj 		  break;
251938fd1498Szrj 		}
252038fd1498Szrj 
252138fd1498Szrj 	      /* We visit only labels from cold section.  We should never hit
252238fd1498Szrj 		 begining of the insn stream here.  */
252338fd1498Szrj 	      insn = PREV_INSN (insn);
252438fd1498Szrj 	    }
252538fd1498Szrj 	}
252638fd1498Szrj     }
252738fd1498Szrj   return false;
252838fd1498Szrj }
252938fd1498Szrj 
253038fd1498Szrj /* Turn REG_EH_REGION notes back into NOTE_INSN_EH_REGION notes.
253138fd1498Szrj    The new note numbers will not refer to region numbers, but
253238fd1498Szrj    instead to call site entries.  */
253338fd1498Szrj 
253438fd1498Szrj static unsigned int
convert_to_eh_region_ranges(void)253538fd1498Szrj convert_to_eh_region_ranges (void)
253638fd1498Szrj {
253738fd1498Szrj   rtx insn;
253838fd1498Szrj   rtx_insn *iter;
253938fd1498Szrj   rtx_note *note;
254038fd1498Szrj   action_hash_type ar_hash (31);
254138fd1498Szrj   int last_action = -3;
254238fd1498Szrj   rtx_insn *last_action_insn = NULL;
254338fd1498Szrj   rtx last_landing_pad = NULL_RTX;
254438fd1498Szrj   rtx_insn *first_no_action_insn = NULL;
254538fd1498Szrj   int call_site = 0;
254638fd1498Szrj   int cur_sec = 0;
254738fd1498Szrj   rtx_insn *section_switch_note = NULL;
254838fd1498Szrj   rtx_insn *first_no_action_insn_before_switch = NULL;
254938fd1498Szrj   rtx_insn *last_no_action_insn_before_switch = NULL;
255038fd1498Szrj   int saved_call_site_base = call_site_base;
255138fd1498Szrj 
255238fd1498Szrj   vec_alloc (crtl->eh.action_record_data, 64);
255338fd1498Szrj 
255438fd1498Szrj   for (iter = get_insns (); iter ; iter = NEXT_INSN (iter))
255538fd1498Szrj     if (INSN_P (iter))
255638fd1498Szrj       {
255738fd1498Szrj 	eh_landing_pad lp;
255838fd1498Szrj 	eh_region region;
255938fd1498Szrj 	bool nothrow;
256038fd1498Szrj 	int this_action;
256138fd1498Szrj 	rtx_code_label *this_landing_pad;
256238fd1498Szrj 
256338fd1498Szrj 	insn = iter;
256438fd1498Szrj 	if (NONJUMP_INSN_P (insn)
256538fd1498Szrj 	    && GET_CODE (PATTERN (insn)) == SEQUENCE)
256638fd1498Szrj 	  insn = XVECEXP (PATTERN (insn), 0, 0);
256738fd1498Szrj 
256838fd1498Szrj 	nothrow = get_eh_region_and_lp_from_rtx (insn, &region, &lp);
256938fd1498Szrj 	if (nothrow)
257038fd1498Szrj 	  continue;
257138fd1498Szrj 	if (region)
257238fd1498Szrj 	  this_action = collect_one_action_chain (&ar_hash, region);
257338fd1498Szrj 	else
257438fd1498Szrj 	  this_action = -1;
257538fd1498Szrj 
257638fd1498Szrj 	/* Existence of catch handlers, or must-not-throw regions
257738fd1498Szrj 	   implies that an lsda is needed (even if empty).  */
257838fd1498Szrj 	if (this_action != -1)
257938fd1498Szrj 	  crtl->uses_eh_lsda = 1;
258038fd1498Szrj 
258138fd1498Szrj 	/* Delay creation of region notes for no-action regions
258238fd1498Szrj 	   until we're sure that an lsda will be required.  */
258338fd1498Szrj 	else if (last_action == -3)
258438fd1498Szrj 	  {
258538fd1498Szrj 	    first_no_action_insn = iter;
258638fd1498Szrj 	    last_action = -1;
258738fd1498Szrj 	  }
258838fd1498Szrj 
258938fd1498Szrj 	if (this_action >= 0)
259038fd1498Szrj 	  this_landing_pad = lp->landing_pad;
259138fd1498Szrj 	else
259238fd1498Szrj 	  this_landing_pad = NULL;
259338fd1498Szrj 
259438fd1498Szrj 	/* Differing actions or landing pads implies a change in call-site
259538fd1498Szrj 	   info, which implies some EH_REGION note should be emitted.  */
259638fd1498Szrj 	if (last_action != this_action
259738fd1498Szrj 	    || last_landing_pad != this_landing_pad)
259838fd1498Szrj 	  {
259938fd1498Szrj 	    /* If there is a queued no-action region in the other section
260038fd1498Szrj 	       with hot/cold partitioning, emit it now.  */
260138fd1498Szrj 	    if (first_no_action_insn_before_switch)
260238fd1498Szrj 	      {
260338fd1498Szrj 		gcc_assert (this_action != -1
260438fd1498Szrj 			    && last_action == (first_no_action_insn
260538fd1498Szrj 					       ? -1 : -3));
260638fd1498Szrj 		call_site = add_call_site (NULL_RTX, 0, 0);
260738fd1498Szrj 		note = emit_note_before (NOTE_INSN_EH_REGION_BEG,
260838fd1498Szrj 					 first_no_action_insn_before_switch);
260938fd1498Szrj 		NOTE_EH_HANDLER (note) = call_site;
261038fd1498Szrj 		note
261138fd1498Szrj 		  = emit_note_eh_region_end (last_no_action_insn_before_switch);
261238fd1498Szrj 		NOTE_EH_HANDLER (note) = call_site;
261338fd1498Szrj 		gcc_assert (last_action != -3
261438fd1498Szrj 			    || (last_action_insn
261538fd1498Szrj 				== last_no_action_insn_before_switch));
261638fd1498Szrj 		first_no_action_insn_before_switch = NULL;
261738fd1498Szrj 		last_no_action_insn_before_switch = NULL;
261838fd1498Szrj 		call_site_base++;
261938fd1498Szrj 	      }
262038fd1498Szrj 	    /* If we'd not seen a previous action (-3) or the previous
262138fd1498Szrj 	       action was must-not-throw (-2), then we do not need an
262238fd1498Szrj 	       end note.  */
262338fd1498Szrj 	    if (last_action >= -1)
262438fd1498Szrj 	      {
262538fd1498Szrj 		/* If we delayed the creation of the begin, do it now.  */
262638fd1498Szrj 		if (first_no_action_insn)
262738fd1498Szrj 		  {
262838fd1498Szrj 		    call_site = add_call_site (NULL_RTX, 0, cur_sec);
262938fd1498Szrj 		    note = emit_note_before (NOTE_INSN_EH_REGION_BEG,
263038fd1498Szrj 					     first_no_action_insn);
263138fd1498Szrj 		    NOTE_EH_HANDLER (note) = call_site;
263238fd1498Szrj 		    first_no_action_insn = NULL;
263338fd1498Szrj 		  }
263438fd1498Szrj 
263538fd1498Szrj 		note = emit_note_eh_region_end (last_action_insn);
263638fd1498Szrj 		NOTE_EH_HANDLER (note) = call_site;
263738fd1498Szrj 	      }
263838fd1498Szrj 
263938fd1498Szrj 	    /* If the new action is must-not-throw, then no region notes
264038fd1498Szrj 	       are created.  */
264138fd1498Szrj 	    if (this_action >= -1)
264238fd1498Szrj 	      {
264338fd1498Szrj 		call_site = add_call_site (this_landing_pad,
264438fd1498Szrj 					   this_action < 0 ? 0 : this_action,
264538fd1498Szrj 					   cur_sec);
264638fd1498Szrj 		note = emit_note_before (NOTE_INSN_EH_REGION_BEG, iter);
264738fd1498Szrj 		NOTE_EH_HANDLER (note) = call_site;
264838fd1498Szrj 	      }
264938fd1498Szrj 
265038fd1498Szrj 	    last_action = this_action;
265138fd1498Szrj 	    last_landing_pad = this_landing_pad;
265238fd1498Szrj 	  }
265338fd1498Szrj 	last_action_insn = iter;
265438fd1498Szrj       }
265538fd1498Szrj     else if (NOTE_P (iter)
265638fd1498Szrj 	     && NOTE_KIND (iter) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
265738fd1498Szrj       {
265838fd1498Szrj 	gcc_assert (section_switch_note == NULL_RTX);
265938fd1498Szrj 	gcc_assert (flag_reorder_blocks_and_partition);
266038fd1498Szrj 	section_switch_note = iter;
266138fd1498Szrj 	if (first_no_action_insn)
266238fd1498Szrj 	  {
266338fd1498Szrj 	    first_no_action_insn_before_switch = first_no_action_insn;
266438fd1498Szrj 	    last_no_action_insn_before_switch = last_action_insn;
266538fd1498Szrj 	    first_no_action_insn = NULL;
266638fd1498Szrj 	    gcc_assert (last_action == -1);
266738fd1498Szrj 	    last_action = -3;
266838fd1498Szrj 	  }
266938fd1498Szrj 	/* Force closing of current EH region before section switch and
267038fd1498Szrj 	   opening a new one afterwards.  */
267138fd1498Szrj 	else if (last_action != -3)
267238fd1498Szrj 	  last_landing_pad = pc_rtx;
267338fd1498Szrj 	if (crtl->eh.call_site_record_v[cur_sec])
267438fd1498Szrj 	  call_site_base += crtl->eh.call_site_record_v[cur_sec]->length ();
267538fd1498Szrj 	cur_sec++;
267638fd1498Szrj 	gcc_assert (crtl->eh.call_site_record_v[cur_sec] == NULL);
267738fd1498Szrj 	vec_alloc (crtl->eh.call_site_record_v[cur_sec], 10);
267838fd1498Szrj       }
267938fd1498Szrj 
268038fd1498Szrj   if (last_action >= -1 && ! first_no_action_insn)
268138fd1498Szrj     {
268238fd1498Szrj       note = emit_note_eh_region_end (last_action_insn);
268338fd1498Szrj       NOTE_EH_HANDLER (note) = call_site;
268438fd1498Szrj     }
268538fd1498Szrj 
268638fd1498Szrj   call_site_base = saved_call_site_base;
268738fd1498Szrj 
268838fd1498Szrj   return 0;
268938fd1498Szrj }
269038fd1498Szrj 
269138fd1498Szrj namespace {
269238fd1498Szrj 
269338fd1498Szrj const pass_data pass_data_convert_to_eh_region_ranges =
269438fd1498Szrj {
269538fd1498Szrj   RTL_PASS, /* type */
269638fd1498Szrj   "eh_ranges", /* name */
269738fd1498Szrj   OPTGROUP_NONE, /* optinfo_flags */
269838fd1498Szrj   TV_NONE, /* tv_id */
269938fd1498Szrj   0, /* properties_required */
270038fd1498Szrj   0, /* properties_provided */
270138fd1498Szrj   0, /* properties_destroyed */
270238fd1498Szrj   0, /* todo_flags_start */
270338fd1498Szrj   0, /* todo_flags_finish */
270438fd1498Szrj };
270538fd1498Szrj 
270638fd1498Szrj class pass_convert_to_eh_region_ranges : public rtl_opt_pass
270738fd1498Szrj {
270838fd1498Szrj public:
pass_convert_to_eh_region_ranges(gcc::context * ctxt)270938fd1498Szrj   pass_convert_to_eh_region_ranges (gcc::context *ctxt)
271038fd1498Szrj     : rtl_opt_pass (pass_data_convert_to_eh_region_ranges, ctxt)
271138fd1498Szrj   {}
271238fd1498Szrj 
271338fd1498Szrj   /* opt_pass methods: */
271438fd1498Szrj   virtual bool gate (function *);
execute(function *)271538fd1498Szrj   virtual unsigned int execute (function *)
271638fd1498Szrj     {
271738fd1498Szrj       int ret = convert_to_eh_region_ranges ();
271838fd1498Szrj       maybe_add_nop_after_section_switch ();
271938fd1498Szrj       return ret;
272038fd1498Szrj     }
272138fd1498Szrj 
272238fd1498Szrj }; // class pass_convert_to_eh_region_ranges
272338fd1498Szrj 
272438fd1498Szrj bool
gate(function *)272538fd1498Szrj pass_convert_to_eh_region_ranges::gate (function *)
272638fd1498Szrj {
272738fd1498Szrj   /* Nothing to do for SJLJ exceptions or if no regions created.  */
272838fd1498Szrj   if (cfun->eh->region_tree == NULL)
272938fd1498Szrj     return false;
273038fd1498Szrj   if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
273138fd1498Szrj     return false;
273238fd1498Szrj   return true;
273338fd1498Szrj }
273438fd1498Szrj 
273538fd1498Szrj } // anon namespace
273638fd1498Szrj 
273738fd1498Szrj rtl_opt_pass *
make_pass_convert_to_eh_region_ranges(gcc::context * ctxt)273838fd1498Szrj make_pass_convert_to_eh_region_ranges (gcc::context *ctxt)
273938fd1498Szrj {
274038fd1498Szrj   return new pass_convert_to_eh_region_ranges (ctxt);
274138fd1498Szrj }
274238fd1498Szrj 
274338fd1498Szrj static void
push_uleb128(vec<uchar,va_gc> ** data_area,unsigned int value)274438fd1498Szrj push_uleb128 (vec<uchar, va_gc> **data_area, unsigned int value)
274538fd1498Szrj {
274638fd1498Szrj   do
274738fd1498Szrj     {
274838fd1498Szrj       unsigned char byte = value & 0x7f;
274938fd1498Szrj       value >>= 7;
275038fd1498Szrj       if (value)
275138fd1498Szrj 	byte |= 0x80;
275238fd1498Szrj       vec_safe_push (*data_area, byte);
275338fd1498Szrj     }
275438fd1498Szrj   while (value);
275538fd1498Szrj }
275638fd1498Szrj 
275738fd1498Szrj static void
push_sleb128(vec<uchar,va_gc> ** data_area,int value)275838fd1498Szrj push_sleb128 (vec<uchar, va_gc> **data_area, int value)
275938fd1498Szrj {
276038fd1498Szrj   unsigned char byte;
276138fd1498Szrj   int more;
276238fd1498Szrj 
276338fd1498Szrj   do
276438fd1498Szrj     {
276538fd1498Szrj       byte = value & 0x7f;
276638fd1498Szrj       value >>= 7;
276738fd1498Szrj       more = ! ((value == 0 && (byte & 0x40) == 0)
276838fd1498Szrj 		|| (value == -1 && (byte & 0x40) != 0));
276938fd1498Szrj       if (more)
277038fd1498Szrj 	byte |= 0x80;
277138fd1498Szrj       vec_safe_push (*data_area, byte);
277238fd1498Szrj     }
277338fd1498Szrj   while (more);
277438fd1498Szrj }
277538fd1498Szrj 
277638fd1498Szrj 
277738fd1498Szrj static int
dw2_size_of_call_site_table(int section)277838fd1498Szrj dw2_size_of_call_site_table (int section)
277938fd1498Szrj {
278038fd1498Szrj   int n = vec_safe_length (crtl->eh.call_site_record_v[section]);
278138fd1498Szrj   int size = n * (4 + 4 + 4);
278238fd1498Szrj   int i;
278338fd1498Szrj 
278438fd1498Szrj   for (i = 0; i < n; ++i)
278538fd1498Szrj     {
278638fd1498Szrj       struct call_site_record_d *cs =
278738fd1498Szrj 	(*crtl->eh.call_site_record_v[section])[i];
278838fd1498Szrj       size += size_of_uleb128 (cs->action);
278938fd1498Szrj     }
279038fd1498Szrj 
279138fd1498Szrj   return size;
279238fd1498Szrj }
279338fd1498Szrj 
279438fd1498Szrj static int
sjlj_size_of_call_site_table(void)279538fd1498Szrj sjlj_size_of_call_site_table (void)
279638fd1498Szrj {
279738fd1498Szrj   int n = vec_safe_length (crtl->eh.call_site_record_v[0]);
279838fd1498Szrj   int size = 0;
279938fd1498Szrj   int i;
280038fd1498Szrj 
280138fd1498Szrj   for (i = 0; i < n; ++i)
280238fd1498Szrj     {
280338fd1498Szrj       struct call_site_record_d *cs =
280438fd1498Szrj 	(*crtl->eh.call_site_record_v[0])[i];
280538fd1498Szrj       size += size_of_uleb128 (INTVAL (cs->landing_pad));
280638fd1498Szrj       size += size_of_uleb128 (cs->action);
280738fd1498Szrj     }
280838fd1498Szrj 
280938fd1498Szrj   return size;
281038fd1498Szrj }
281138fd1498Szrj 
281238fd1498Szrj static void
dw2_output_call_site_table(int cs_format,int section)281338fd1498Szrj dw2_output_call_site_table (int cs_format, int section)
281438fd1498Szrj {
281538fd1498Szrj   int n = vec_safe_length (crtl->eh.call_site_record_v[section]);
281638fd1498Szrj   int i;
281738fd1498Szrj   const char *begin;
281838fd1498Szrj 
281938fd1498Szrj   if (section == 0)
282038fd1498Szrj     begin = current_function_func_begin_label;
282138fd1498Szrj   else if (first_function_block_is_cold)
282238fd1498Szrj     begin = crtl->subsections.hot_section_label;
282338fd1498Szrj   else
282438fd1498Szrj     begin = crtl->subsections.cold_section_label;
282538fd1498Szrj 
282638fd1498Szrj   for (i = 0; i < n; ++i)
282738fd1498Szrj     {
282838fd1498Szrj       struct call_site_record_d *cs = (*crtl->eh.call_site_record_v[section])[i];
282938fd1498Szrj       char reg_start_lab[32];
283038fd1498Szrj       char reg_end_lab[32];
283138fd1498Szrj       char landing_pad_lab[32];
283238fd1498Szrj 
283338fd1498Szrj       ASM_GENERATE_INTERNAL_LABEL (reg_start_lab, "LEHB", call_site_base + i);
283438fd1498Szrj       ASM_GENERATE_INTERNAL_LABEL (reg_end_lab, "LEHE", call_site_base + i);
283538fd1498Szrj 
283638fd1498Szrj       if (cs->landing_pad)
283738fd1498Szrj 	ASM_GENERATE_INTERNAL_LABEL (landing_pad_lab, "L",
283838fd1498Szrj 				     CODE_LABEL_NUMBER (cs->landing_pad));
283938fd1498Szrj 
284038fd1498Szrj       /* ??? Perhaps use insn length scaling if the assembler supports
284138fd1498Szrj 	 generic arithmetic.  */
284238fd1498Szrj       /* ??? Perhaps use attr_length to choose data1 or data2 instead of
284338fd1498Szrj 	 data4 if the function is small enough.  */
284438fd1498Szrj       if (cs_format == DW_EH_PE_uleb128)
284538fd1498Szrj 	{
284638fd1498Szrj 	  dw2_asm_output_delta_uleb128 (reg_start_lab, begin,
284738fd1498Szrj 					"region %d start", i);
284838fd1498Szrj 	  dw2_asm_output_delta_uleb128 (reg_end_lab, reg_start_lab,
284938fd1498Szrj 					"length");
285038fd1498Szrj 	  if (cs->landing_pad)
285138fd1498Szrj 	    dw2_asm_output_delta_uleb128 (landing_pad_lab, begin,
285238fd1498Szrj 					  "landing pad");
285338fd1498Szrj 	  else
285438fd1498Szrj 	    dw2_asm_output_data_uleb128 (0, "landing pad");
285538fd1498Szrj 	}
285638fd1498Szrj       else
285738fd1498Szrj 	{
285838fd1498Szrj 	  dw2_asm_output_delta (4, reg_start_lab, begin,
285938fd1498Szrj 				"region %d start", i);
286038fd1498Szrj 	  dw2_asm_output_delta (4, reg_end_lab, reg_start_lab, "length");
286138fd1498Szrj 	  if (cs->landing_pad)
286238fd1498Szrj 	    dw2_asm_output_delta (4, landing_pad_lab, begin,
286338fd1498Szrj 				  "landing pad");
286438fd1498Szrj 	  else
286538fd1498Szrj 	    dw2_asm_output_data (4, 0, "landing pad");
286638fd1498Szrj 	}
286738fd1498Szrj       dw2_asm_output_data_uleb128 (cs->action, "action");
286838fd1498Szrj     }
286938fd1498Szrj 
287038fd1498Szrj   call_site_base += n;
287138fd1498Szrj }
287238fd1498Szrj 
287338fd1498Szrj static void
sjlj_output_call_site_table(void)287438fd1498Szrj sjlj_output_call_site_table (void)
287538fd1498Szrj {
287638fd1498Szrj   int n = vec_safe_length (crtl->eh.call_site_record_v[0]);
287738fd1498Szrj   int i;
287838fd1498Szrj 
287938fd1498Szrj   for (i = 0; i < n; ++i)
288038fd1498Szrj     {
288138fd1498Szrj       struct call_site_record_d *cs = (*crtl->eh.call_site_record_v[0])[i];
288238fd1498Szrj 
288338fd1498Szrj       dw2_asm_output_data_uleb128 (INTVAL (cs->landing_pad),
288438fd1498Szrj 				   "region %d landing pad", i);
288538fd1498Szrj       dw2_asm_output_data_uleb128 (cs->action, "action");
288638fd1498Szrj     }
288738fd1498Szrj 
288838fd1498Szrj   call_site_base += n;
288938fd1498Szrj }
289038fd1498Szrj 
289138fd1498Szrj /* Switch to the section that should be used for exception tables.  */
289238fd1498Szrj 
289338fd1498Szrj static void
switch_to_exception_section(const char * ARG_UNUSED (fnname))289438fd1498Szrj switch_to_exception_section (const char * ARG_UNUSED (fnname))
289538fd1498Szrj {
289638fd1498Szrj   section *s;
289738fd1498Szrj 
289838fd1498Szrj   if (exception_section)
289938fd1498Szrj     s = exception_section;
290038fd1498Szrj   else
290138fd1498Szrj     {
290238fd1498Szrj       int flags;
290338fd1498Szrj 
290438fd1498Szrj       if (EH_TABLES_CAN_BE_READ_ONLY)
290538fd1498Szrj 	{
290638fd1498Szrj 	  int tt_format =
290738fd1498Szrj 	    ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
290838fd1498Szrj 	  flags = ((! flag_pic
290938fd1498Szrj 		    || ((tt_format & 0x70) != DW_EH_PE_absptr
291038fd1498Szrj 			&& (tt_format & 0x70) != DW_EH_PE_aligned))
291138fd1498Szrj 		   ? 0 : SECTION_WRITE);
291238fd1498Szrj 	}
291338fd1498Szrj       else
291438fd1498Szrj 	flags = SECTION_WRITE;
291538fd1498Szrj 
291638fd1498Szrj       /* Compute the section and cache it into exception_section,
291738fd1498Szrj 	 unless it depends on the function name.  */
291838fd1498Szrj       if (targetm_common.have_named_sections)
291938fd1498Szrj 	{
292038fd1498Szrj #ifdef HAVE_LD_EH_GC_SECTIONS
292138fd1498Szrj 	  if (flag_function_sections
292238fd1498Szrj 	      || (DECL_COMDAT_GROUP (current_function_decl) && HAVE_COMDAT_GROUP))
292338fd1498Szrj 	    {
292438fd1498Szrj 	      char *section_name = XNEWVEC (char, strlen (fnname) + 32);
292538fd1498Szrj 	      /* The EH table must match the code section, so only mark
292638fd1498Szrj 		 it linkonce if we have COMDAT groups to tie them together.  */
292738fd1498Szrj 	      if (DECL_COMDAT_GROUP (current_function_decl) && HAVE_COMDAT_GROUP)
292838fd1498Szrj 		flags |= SECTION_LINKONCE;
292938fd1498Szrj 	      sprintf (section_name, ".gcc_except_table.%s", fnname);
293038fd1498Szrj 	      s = get_section (section_name, flags, current_function_decl);
293138fd1498Szrj 	      free (section_name);
293238fd1498Szrj 	    }
293338fd1498Szrj 	  else
293438fd1498Szrj #endif
293538fd1498Szrj 	    exception_section
293638fd1498Szrj 	      = s = get_section (".gcc_except_table", flags, NULL);
293738fd1498Szrj 	}
293838fd1498Szrj       else
293938fd1498Szrj 	exception_section
294038fd1498Szrj 	  = s = flags == SECTION_WRITE ? data_section : readonly_data_section;
294138fd1498Szrj     }
294238fd1498Szrj 
294338fd1498Szrj   switch_to_section (s);
294438fd1498Szrj }
294538fd1498Szrj 
294638fd1498Szrj /* Output a reference from an exception table to the type_info object TYPE.
294738fd1498Szrj    TT_FORMAT and TT_FORMAT_SIZE describe the DWARF encoding method used for
294838fd1498Szrj    the value.  */
294938fd1498Szrj 
295038fd1498Szrj static void
output_ttype(tree type,int tt_format,int tt_format_size)295138fd1498Szrj output_ttype (tree type, int tt_format, int tt_format_size)
295238fd1498Szrj {
295338fd1498Szrj   rtx value;
295438fd1498Szrj   bool is_public = true;
295538fd1498Szrj 
295638fd1498Szrj   if (type == NULL_TREE)
295738fd1498Szrj     value = const0_rtx;
295838fd1498Szrj   else
295938fd1498Szrj     {
296038fd1498Szrj       /* FIXME lto.  pass_ipa_free_lang_data changes all types to
296138fd1498Szrj 	 runtime types so TYPE should already be a runtime type
296238fd1498Szrj 	 reference.  When pass_ipa_free_lang data is made a default
296338fd1498Szrj 	 pass, we can then remove the call to lookup_type_for_runtime
296438fd1498Szrj 	 below.  */
296538fd1498Szrj       if (TYPE_P (type))
296638fd1498Szrj 	type = lookup_type_for_runtime (type);
296738fd1498Szrj 
296838fd1498Szrj       value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
296938fd1498Szrj 
297038fd1498Szrj       /* Let cgraph know that the rtti decl is used.  Not all of the
297138fd1498Szrj 	 paths below go through assemble_integer, which would take
297238fd1498Szrj 	 care of this for us.  */
297338fd1498Szrj       STRIP_NOPS (type);
297438fd1498Szrj       if (TREE_CODE (type) == ADDR_EXPR)
297538fd1498Szrj 	{
297638fd1498Szrj 	  type = TREE_OPERAND (type, 0);
297738fd1498Szrj 	  if (VAR_P (type))
297838fd1498Szrj 	    is_public = TREE_PUBLIC (type);
297938fd1498Szrj 	}
298038fd1498Szrj       else
298138fd1498Szrj 	gcc_assert (TREE_CODE (type) == INTEGER_CST);
298238fd1498Szrj     }
298338fd1498Szrj 
298438fd1498Szrj   /* Allow the target to override the type table entry format.  */
298538fd1498Szrj   if (targetm.asm_out.ttype (value))
298638fd1498Szrj     return;
298738fd1498Szrj 
298838fd1498Szrj   if (tt_format == DW_EH_PE_absptr || tt_format == DW_EH_PE_aligned)
298938fd1498Szrj     assemble_integer (value, tt_format_size,
299038fd1498Szrj 		      tt_format_size * BITS_PER_UNIT, 1);
299138fd1498Szrj   else
299238fd1498Szrj     dw2_asm_output_encoded_addr_rtx (tt_format, value, is_public, NULL);
299338fd1498Szrj }
299438fd1498Szrj 
299538fd1498Szrj /* Output an exception table for the current function according to SECTION.
299638fd1498Szrj 
299738fd1498Szrj    If the function has been partitioned into hot and cold parts, value 0 for
299838fd1498Szrj    SECTION refers to the table associated with the hot part while value 1
299938fd1498Szrj    refers to the table associated with the cold part.  If the function has
300038fd1498Szrj    not been partitioned, value 0 refers to the single exception table.  */
300138fd1498Szrj 
300238fd1498Szrj static void
output_one_function_exception_table(int section)300338fd1498Szrj output_one_function_exception_table (int section)
300438fd1498Szrj {
300538fd1498Szrj   int tt_format, cs_format, lp_format, i;
300638fd1498Szrj   char ttype_label[32];
300738fd1498Szrj   char cs_after_size_label[32];
300838fd1498Szrj   char cs_end_label[32];
300938fd1498Szrj   int call_site_len;
301038fd1498Szrj   int have_tt_data;
301138fd1498Szrj   int tt_format_size = 0;
301238fd1498Szrj 
301338fd1498Szrj   have_tt_data = (vec_safe_length (cfun->eh->ttype_data)
301438fd1498Szrj 		  || (targetm.arm_eabi_unwinder
301538fd1498Szrj 		      ? vec_safe_length (cfun->eh->ehspec_data.arm_eabi)
301638fd1498Szrj 		      : vec_safe_length (cfun->eh->ehspec_data.other)));
301738fd1498Szrj 
301838fd1498Szrj   /* Indicate the format of the @TType entries.  */
301938fd1498Szrj   if (! have_tt_data)
302038fd1498Szrj     tt_format = DW_EH_PE_omit;
302138fd1498Szrj   else
302238fd1498Szrj     {
302338fd1498Szrj       tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
302438fd1498Szrj       if (HAVE_AS_LEB128)
302538fd1498Szrj 	ASM_GENERATE_INTERNAL_LABEL (ttype_label,
302638fd1498Szrj 				     section ? "LLSDATTC" : "LLSDATT",
302738fd1498Szrj 				     current_function_funcdef_no);
302838fd1498Szrj 
302938fd1498Szrj       tt_format_size = size_of_encoded_value (tt_format);
303038fd1498Szrj 
303138fd1498Szrj       assemble_align (tt_format_size * BITS_PER_UNIT);
303238fd1498Szrj     }
303338fd1498Szrj 
303438fd1498Szrj   targetm.asm_out.internal_label (asm_out_file, section ? "LLSDAC" : "LLSDA",
303538fd1498Szrj 				  current_function_funcdef_no);
303638fd1498Szrj 
303738fd1498Szrj   /* The LSDA header.  */
303838fd1498Szrj 
303938fd1498Szrj   /* Indicate the format of the landing pad start pointer.  An omitted
304038fd1498Szrj      field implies @LPStart == @Start.  */
304138fd1498Szrj   /* Currently we always put @LPStart == @Start.  This field would
304238fd1498Szrj      be most useful in moving the landing pads completely out of
304338fd1498Szrj      line to another section, but it could also be used to minimize
304438fd1498Szrj      the size of uleb128 landing pad offsets.  */
304538fd1498Szrj   lp_format = DW_EH_PE_omit;
304638fd1498Szrj   dw2_asm_output_data (1, lp_format, "@LPStart format (%s)",
304738fd1498Szrj 		       eh_data_format_name (lp_format));
304838fd1498Szrj 
304938fd1498Szrj   /* @LPStart pointer would go here.  */
305038fd1498Szrj 
305138fd1498Szrj   dw2_asm_output_data (1, tt_format, "@TType format (%s)",
305238fd1498Szrj 		       eh_data_format_name (tt_format));
305338fd1498Szrj 
305438fd1498Szrj   if (!HAVE_AS_LEB128)
305538fd1498Szrj     {
305638fd1498Szrj       if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
305738fd1498Szrj 	call_site_len = sjlj_size_of_call_site_table ();
305838fd1498Szrj       else
305938fd1498Szrj 	call_site_len = dw2_size_of_call_site_table (section);
306038fd1498Szrj     }
306138fd1498Szrj 
306238fd1498Szrj   /* A pc-relative 4-byte displacement to the @TType data.  */
306338fd1498Szrj   if (have_tt_data)
306438fd1498Szrj     {
306538fd1498Szrj       if (HAVE_AS_LEB128)
306638fd1498Szrj 	{
306738fd1498Szrj 	  char ttype_after_disp_label[32];
306838fd1498Szrj 	  ASM_GENERATE_INTERNAL_LABEL (ttype_after_disp_label,
306938fd1498Szrj 				       section ? "LLSDATTDC" : "LLSDATTD",
307038fd1498Szrj 				       current_function_funcdef_no);
307138fd1498Szrj 	  dw2_asm_output_delta_uleb128 (ttype_label, ttype_after_disp_label,
307238fd1498Szrj 					"@TType base offset");
307338fd1498Szrj 	  ASM_OUTPUT_LABEL (asm_out_file, ttype_after_disp_label);
307438fd1498Szrj 	}
307538fd1498Szrj       else
307638fd1498Szrj 	{
307738fd1498Szrj 	  /* Ug.  Alignment queers things.  */
307838fd1498Szrj 	  unsigned int before_disp, after_disp, last_disp, disp;
307938fd1498Szrj 
308038fd1498Szrj 	  before_disp = 1 + 1;
308138fd1498Szrj 	  after_disp = (1 + size_of_uleb128 (call_site_len)
308238fd1498Szrj 			+ call_site_len
308338fd1498Szrj 			+ vec_safe_length (crtl->eh.action_record_data)
308438fd1498Szrj 			+ (vec_safe_length (cfun->eh->ttype_data)
308538fd1498Szrj 			   * tt_format_size));
308638fd1498Szrj 
308738fd1498Szrj 	  disp = after_disp;
308838fd1498Szrj 	  do
308938fd1498Szrj 	    {
309038fd1498Szrj 	      unsigned int disp_size, pad;
309138fd1498Szrj 
309238fd1498Szrj 	      last_disp = disp;
309338fd1498Szrj 	      disp_size = size_of_uleb128 (disp);
309438fd1498Szrj 	      pad = before_disp + disp_size + after_disp;
309538fd1498Szrj 	      if (pad % tt_format_size)
309638fd1498Szrj 		pad = tt_format_size - (pad % tt_format_size);
309738fd1498Szrj 	      else
309838fd1498Szrj 		pad = 0;
309938fd1498Szrj 	      disp = after_disp + pad;
310038fd1498Szrj 	    }
310138fd1498Szrj 	  while (disp != last_disp);
310238fd1498Szrj 
310338fd1498Szrj 	  dw2_asm_output_data_uleb128 (disp, "@TType base offset");
310438fd1498Szrj 	}
310538fd1498Szrj 	}
310638fd1498Szrj 
310738fd1498Szrj   /* Indicate the format of the call-site offsets.  */
310838fd1498Szrj   if (HAVE_AS_LEB128)
310938fd1498Szrj     cs_format = DW_EH_PE_uleb128;
311038fd1498Szrj   else
311138fd1498Szrj     cs_format = DW_EH_PE_udata4;
311238fd1498Szrj 
311338fd1498Szrj   dw2_asm_output_data (1, cs_format, "call-site format (%s)",
311438fd1498Szrj 		       eh_data_format_name (cs_format));
311538fd1498Szrj 
311638fd1498Szrj   if (HAVE_AS_LEB128)
311738fd1498Szrj     {
311838fd1498Szrj       ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label,
311938fd1498Szrj 				   section ? "LLSDACSBC" : "LLSDACSB",
312038fd1498Szrj 				   current_function_funcdef_no);
312138fd1498Szrj       ASM_GENERATE_INTERNAL_LABEL (cs_end_label,
312238fd1498Szrj 				   section ? "LLSDACSEC" : "LLSDACSE",
312338fd1498Szrj 				   current_function_funcdef_no);
312438fd1498Szrj       dw2_asm_output_delta_uleb128 (cs_end_label, cs_after_size_label,
312538fd1498Szrj 				    "Call-site table length");
312638fd1498Szrj       ASM_OUTPUT_LABEL (asm_out_file, cs_after_size_label);
312738fd1498Szrj       if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
312838fd1498Szrj 	sjlj_output_call_site_table ();
312938fd1498Szrj       else
313038fd1498Szrj 	dw2_output_call_site_table (cs_format, section);
313138fd1498Szrj       ASM_OUTPUT_LABEL (asm_out_file, cs_end_label);
313238fd1498Szrj     }
313338fd1498Szrj   else
313438fd1498Szrj     {
313538fd1498Szrj       dw2_asm_output_data_uleb128 (call_site_len, "Call-site table length");
313638fd1498Szrj       if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
313738fd1498Szrj 	sjlj_output_call_site_table ();
313838fd1498Szrj       else
313938fd1498Szrj 	dw2_output_call_site_table (cs_format, section);
314038fd1498Szrj     }
314138fd1498Szrj 
314238fd1498Szrj   /* ??? Decode and interpret the data for flag_debug_asm.  */
314338fd1498Szrj   {
314438fd1498Szrj     uchar uc;
314538fd1498Szrj     FOR_EACH_VEC_ELT (*crtl->eh.action_record_data, i, uc)
314638fd1498Szrj       dw2_asm_output_data (1, uc, i ? NULL : "Action record table");
314738fd1498Szrj   }
314838fd1498Szrj 
314938fd1498Szrj   if (have_tt_data)
315038fd1498Szrj     assemble_align (tt_format_size * BITS_PER_UNIT);
315138fd1498Szrj 
315238fd1498Szrj   i = vec_safe_length (cfun->eh->ttype_data);
315338fd1498Szrj   while (i-- > 0)
315438fd1498Szrj     {
315538fd1498Szrj       tree type = (*cfun->eh->ttype_data)[i];
315638fd1498Szrj       output_ttype (type, tt_format, tt_format_size);
315738fd1498Szrj     }
315838fd1498Szrj 
315938fd1498Szrj   if (HAVE_AS_LEB128 && have_tt_data)
316038fd1498Szrj     ASM_OUTPUT_LABEL (asm_out_file, ttype_label);
316138fd1498Szrj 
316238fd1498Szrj   /* ??? Decode and interpret the data for flag_debug_asm.  */
316338fd1498Szrj   if (targetm.arm_eabi_unwinder)
316438fd1498Szrj     {
316538fd1498Szrj       tree type;
316638fd1498Szrj       for (i = 0;
316738fd1498Szrj 	   vec_safe_iterate (cfun->eh->ehspec_data.arm_eabi, i, &type); ++i)
316838fd1498Szrj 	output_ttype (type, tt_format, tt_format_size);
316938fd1498Szrj     }
317038fd1498Szrj   else
317138fd1498Szrj     {
317238fd1498Szrj       uchar uc;
317338fd1498Szrj       for (i = 0;
317438fd1498Szrj 	   vec_safe_iterate (cfun->eh->ehspec_data.other, i, &uc); ++i)
317538fd1498Szrj 	dw2_asm_output_data (1, uc,
317638fd1498Szrj 			     i ? NULL : "Exception specification table");
317738fd1498Szrj     }
317838fd1498Szrj }
317938fd1498Szrj 
318038fd1498Szrj /* Output an exception table for the current function according to SECTION,
318138fd1498Szrj    switching back and forth from the function section appropriately.
318238fd1498Szrj 
318338fd1498Szrj    If the function has been partitioned into hot and cold parts, value 0 for
318438fd1498Szrj    SECTION refers to the table associated with the hot part while value 1
318538fd1498Szrj    refers to the table associated with the cold part.  If the function has
318638fd1498Szrj    not been partitioned, value 0 refers to the single exception table.  */
318738fd1498Szrj 
318838fd1498Szrj void
output_function_exception_table(int section)318938fd1498Szrj output_function_exception_table (int section)
319038fd1498Szrj {
319138fd1498Szrj   const char *fnname = get_fnname_from_decl (current_function_decl);
319238fd1498Szrj   rtx personality = get_personality_function (current_function_decl);
319338fd1498Szrj 
319438fd1498Szrj   /* Not all functions need anything.  */
319538fd1498Szrj   if (!crtl->uses_eh_lsda)
319638fd1498Szrj     return;
319738fd1498Szrj 
319838fd1498Szrj   /* No need to emit any boilerplate stuff for the cold part.  */
319938fd1498Szrj   if (section == 1 && !crtl->eh.call_site_record_v[1])
320038fd1498Szrj     return;
320138fd1498Szrj 
320238fd1498Szrj   if (personality)
320338fd1498Szrj     {
320438fd1498Szrj       assemble_external_libcall (personality);
320538fd1498Szrj 
320638fd1498Szrj       if (targetm.asm_out.emit_except_personality)
320738fd1498Szrj 	targetm.asm_out.emit_except_personality (personality);
320838fd1498Szrj     }
320938fd1498Szrj 
321038fd1498Szrj   switch_to_exception_section (fnname);
321138fd1498Szrj 
321238fd1498Szrj   /* If the target wants a label to begin the table, emit it here.  */
321338fd1498Szrj   targetm.asm_out.emit_except_table_label (asm_out_file);
321438fd1498Szrj 
321538fd1498Szrj   /* Do the real work.  */
321638fd1498Szrj   output_one_function_exception_table (section);
321738fd1498Szrj 
321838fd1498Szrj   switch_to_section (current_function_section ());
321938fd1498Szrj }
322038fd1498Szrj 
322138fd1498Szrj void
set_eh_throw_stmt_table(function * fun,hash_map<gimple *,int> * table)322238fd1498Szrj set_eh_throw_stmt_table (function *fun, hash_map<gimple *, int> *table)
322338fd1498Szrj {
322438fd1498Szrj   fun->eh->throw_stmt_table = table;
322538fd1498Szrj }
322638fd1498Szrj 
322738fd1498Szrj hash_map<gimple *, int> *
get_eh_throw_stmt_table(struct function * fun)322838fd1498Szrj get_eh_throw_stmt_table (struct function *fun)
322938fd1498Szrj {
323038fd1498Szrj   return fun->eh->throw_stmt_table;
323138fd1498Szrj }
323238fd1498Szrj 
323338fd1498Szrj /* Determine if the function needs an EH personality function.  */
323438fd1498Szrj 
323538fd1498Szrj enum eh_personality_kind
function_needs_eh_personality(struct function * fn)323638fd1498Szrj function_needs_eh_personality (struct function *fn)
323738fd1498Szrj {
323838fd1498Szrj   enum eh_personality_kind kind = eh_personality_none;
323938fd1498Szrj   eh_region i;
324038fd1498Szrj 
324138fd1498Szrj   FOR_ALL_EH_REGION_FN (i, fn)
324238fd1498Szrj     {
324338fd1498Szrj       switch (i->type)
324438fd1498Szrj 	{
324538fd1498Szrj 	case ERT_CLEANUP:
324638fd1498Szrj 	  /* Can do with any personality including the generic C one.  */
324738fd1498Szrj 	  kind = eh_personality_any;
324838fd1498Szrj 	  break;
324938fd1498Szrj 
325038fd1498Szrj 	case ERT_TRY:
325138fd1498Szrj 	case ERT_ALLOWED_EXCEPTIONS:
325238fd1498Szrj 	  /* Always needs a EH personality function.  The generic C
325338fd1498Szrj 	     personality doesn't handle these even for empty type lists.  */
325438fd1498Szrj 	  return eh_personality_lang;
325538fd1498Szrj 
325638fd1498Szrj 	case ERT_MUST_NOT_THROW:
325738fd1498Szrj 	  /* Always needs a EH personality function.  The language may specify
325838fd1498Szrj 	     what abort routine that must be used, e.g. std::terminate.  */
325938fd1498Szrj 	  return eh_personality_lang;
326038fd1498Szrj 	}
326138fd1498Szrj     }
326238fd1498Szrj 
326338fd1498Szrj   return kind;
326438fd1498Szrj }
326538fd1498Szrj 
326638fd1498Szrj /* Dump EH information to OUT.  */
326738fd1498Szrj 
326838fd1498Szrj void
dump_eh_tree(FILE * out,struct function * fun)326938fd1498Szrj dump_eh_tree (FILE * out, struct function *fun)
327038fd1498Szrj {
327138fd1498Szrj   eh_region i;
327238fd1498Szrj   int depth = 0;
327338fd1498Szrj   static const char *const type_name[] = {
327438fd1498Szrj     "cleanup", "try", "allowed_exceptions", "must_not_throw"
327538fd1498Szrj   };
327638fd1498Szrj 
327738fd1498Szrj   i = fun->eh->region_tree;
327838fd1498Szrj   if (!i)
327938fd1498Szrj     return;
328038fd1498Szrj 
328138fd1498Szrj   fprintf (out, "Eh tree:\n");
328238fd1498Szrj   while (1)
328338fd1498Szrj     {
328438fd1498Szrj       fprintf (out, "  %*s %i %s", depth * 2, "",
328538fd1498Szrj 	       i->index, type_name[(int) i->type]);
328638fd1498Szrj 
328738fd1498Szrj       if (i->landing_pads)
328838fd1498Szrj 	{
328938fd1498Szrj 	  eh_landing_pad lp;
329038fd1498Szrj 
329138fd1498Szrj 	  fprintf (out, " land:");
329238fd1498Szrj 	  if (current_ir_type () == IR_GIMPLE)
329338fd1498Szrj 	    {
329438fd1498Szrj 	      for (lp = i->landing_pads; lp ; lp = lp->next_lp)
329538fd1498Szrj 		{
329638fd1498Szrj 		  fprintf (out, "{%i,", lp->index);
329738fd1498Szrj 		  print_generic_expr (out, lp->post_landing_pad);
329838fd1498Szrj 		  fputc ('}', out);
329938fd1498Szrj 		  if (lp->next_lp)
330038fd1498Szrj 		    fputc (',', out);
330138fd1498Szrj 		}
330238fd1498Szrj 	    }
330338fd1498Szrj 	  else
330438fd1498Szrj 	    {
330538fd1498Szrj 	      for (lp = i->landing_pads; lp ; lp = lp->next_lp)
330638fd1498Szrj 		{
330738fd1498Szrj 		  fprintf (out, "{%i,", lp->index);
330838fd1498Szrj 		  if (lp->landing_pad)
330938fd1498Szrj 		    fprintf (out, "%i%s,", INSN_UID (lp->landing_pad),
331038fd1498Szrj 			     NOTE_P (lp->landing_pad) ? "(del)" : "");
331138fd1498Szrj 		  else
331238fd1498Szrj 		    fprintf (out, "(nil),");
331338fd1498Szrj 		  if (lp->post_landing_pad)
331438fd1498Szrj 		    {
331538fd1498Szrj 		      rtx_insn *lab = label_rtx (lp->post_landing_pad);
331638fd1498Szrj 		      fprintf (out, "%i%s}", INSN_UID (lab),
331738fd1498Szrj 			       NOTE_P (lab) ? "(del)" : "");
331838fd1498Szrj 		    }
331938fd1498Szrj 		  else
332038fd1498Szrj 		    fprintf (out, "(nil)}");
332138fd1498Szrj 		  if (lp->next_lp)
332238fd1498Szrj 		    fputc (',', out);
332338fd1498Szrj 		}
332438fd1498Szrj 	    }
332538fd1498Szrj 	}
332638fd1498Szrj 
332738fd1498Szrj       switch (i->type)
332838fd1498Szrj 	{
332938fd1498Szrj 	case ERT_CLEANUP:
333038fd1498Szrj 	case ERT_MUST_NOT_THROW:
333138fd1498Szrj 	  break;
333238fd1498Szrj 
333338fd1498Szrj 	case ERT_TRY:
333438fd1498Szrj 	  {
333538fd1498Szrj 	    eh_catch c;
333638fd1498Szrj 	    fprintf (out, " catch:");
333738fd1498Szrj 	    for (c = i->u.eh_try.first_catch; c; c = c->next_catch)
333838fd1498Szrj 	      {
333938fd1498Szrj 		fputc ('{', out);
334038fd1498Szrj 		if (c->label)
334138fd1498Szrj 		  {
334238fd1498Szrj 		    fprintf (out, "lab:");
334338fd1498Szrj 		    print_generic_expr (out, c->label);
334438fd1498Szrj 		    fputc (';', out);
334538fd1498Szrj 		  }
334638fd1498Szrj 		print_generic_expr (out, c->type_list);
334738fd1498Szrj 		fputc ('}', out);
334838fd1498Szrj 		if (c->next_catch)
334938fd1498Szrj 		  fputc (',', out);
335038fd1498Szrj 	      }
335138fd1498Szrj 	  }
335238fd1498Szrj 	  break;
335338fd1498Szrj 
335438fd1498Szrj 	case ERT_ALLOWED_EXCEPTIONS:
335538fd1498Szrj 	  fprintf (out, " filter :%i types:", i->u.allowed.filter);
335638fd1498Szrj 	  print_generic_expr (out, i->u.allowed.type_list);
335738fd1498Szrj 	  break;
335838fd1498Szrj 	}
335938fd1498Szrj       fputc ('\n', out);
336038fd1498Szrj 
336138fd1498Szrj       /* If there are sub-regions, process them.  */
336238fd1498Szrj       if (i->inner)
336338fd1498Szrj 	i = i->inner, depth++;
336438fd1498Szrj       /* If there are peers, process them.  */
336538fd1498Szrj       else if (i->next_peer)
336638fd1498Szrj 	i = i->next_peer;
336738fd1498Szrj       /* Otherwise, step back up the tree to the next peer.  */
336838fd1498Szrj       else
336938fd1498Szrj 	{
337038fd1498Szrj 	  do
337138fd1498Szrj 	    {
337238fd1498Szrj 	      i = i->outer;
337338fd1498Szrj 	      depth--;
337438fd1498Szrj 	      if (i == NULL)
337538fd1498Szrj 		return;
337638fd1498Szrj 	    }
337738fd1498Szrj 	  while (i->next_peer == NULL);
337838fd1498Szrj 	  i = i->next_peer;
337938fd1498Szrj 	}
338038fd1498Szrj     }
338138fd1498Szrj }
338238fd1498Szrj 
338338fd1498Szrj /* Dump the EH tree for FN on stderr.  */
338438fd1498Szrj 
338538fd1498Szrj DEBUG_FUNCTION void
debug_eh_tree(struct function * fn)338638fd1498Szrj debug_eh_tree (struct function *fn)
338738fd1498Szrj {
338838fd1498Szrj   dump_eh_tree (stderr, fn);
338938fd1498Szrj }
339038fd1498Szrj 
339138fd1498Szrj /* Verify invariants on EH datastructures.  */
339238fd1498Szrj 
339338fd1498Szrj DEBUG_FUNCTION void
verify_eh_tree(struct function * fun)339438fd1498Szrj verify_eh_tree (struct function *fun)
339538fd1498Szrj {
339638fd1498Szrj   eh_region r, outer;
339738fd1498Szrj   int nvisited_lp, nvisited_r;
339838fd1498Szrj   int count_lp, count_r, depth, i;
339938fd1498Szrj   eh_landing_pad lp;
340038fd1498Szrj   bool err = false;
340138fd1498Szrj 
340238fd1498Szrj   if (!fun->eh->region_tree)
340338fd1498Szrj     return;
340438fd1498Szrj 
340538fd1498Szrj   count_r = 0;
340638fd1498Szrj   for (i = 1; vec_safe_iterate (fun->eh->region_array, i, &r); ++i)
340738fd1498Szrj     if (r)
340838fd1498Szrj       {
340938fd1498Szrj 	if (r->index == i)
341038fd1498Szrj 	  count_r++;
341138fd1498Szrj 	else
341238fd1498Szrj 	  {
341338fd1498Szrj 	    error ("region_array is corrupted for region %i", r->index);
341438fd1498Szrj 	    err = true;
341538fd1498Szrj 	  }
341638fd1498Szrj       }
341738fd1498Szrj 
341838fd1498Szrj   count_lp = 0;
341938fd1498Szrj   for (i = 1; vec_safe_iterate (fun->eh->lp_array, i, &lp); ++i)
342038fd1498Szrj     if (lp)
342138fd1498Szrj       {
342238fd1498Szrj 	if (lp->index == i)
342338fd1498Szrj 	  count_lp++;
342438fd1498Szrj 	else
342538fd1498Szrj 	  {
342638fd1498Szrj 	    error ("lp_array is corrupted for lp %i", lp->index);
342738fd1498Szrj 	    err = true;
342838fd1498Szrj 	  }
342938fd1498Szrj       }
343038fd1498Szrj 
343138fd1498Szrj   depth = nvisited_lp = nvisited_r = 0;
343238fd1498Szrj   outer = NULL;
343338fd1498Szrj   r = fun->eh->region_tree;
343438fd1498Szrj   while (1)
343538fd1498Szrj     {
343638fd1498Szrj       if ((*fun->eh->region_array)[r->index] != r)
343738fd1498Szrj 	{
343838fd1498Szrj 	  error ("region_array is corrupted for region %i", r->index);
343938fd1498Szrj 	  err = true;
344038fd1498Szrj 	}
344138fd1498Szrj       if (r->outer != outer)
344238fd1498Szrj 	{
344338fd1498Szrj 	  error ("outer block of region %i is wrong", r->index);
344438fd1498Szrj 	  err = true;
344538fd1498Szrj 	}
344638fd1498Szrj       if (depth < 0)
344738fd1498Szrj 	{
344838fd1498Szrj 	  error ("negative nesting depth of region %i", r->index);
344938fd1498Szrj 	  err = true;
345038fd1498Szrj 	}
345138fd1498Szrj       nvisited_r++;
345238fd1498Szrj 
345338fd1498Szrj       for (lp = r->landing_pads; lp ; lp = lp->next_lp)
345438fd1498Szrj 	{
345538fd1498Szrj 	  if ((*fun->eh->lp_array)[lp->index] != lp)
345638fd1498Szrj 	    {
345738fd1498Szrj 	      error ("lp_array is corrupted for lp %i", lp->index);
345838fd1498Szrj 	      err = true;
345938fd1498Szrj 	    }
346038fd1498Szrj 	  if (lp->region != r)
346138fd1498Szrj 	    {
346238fd1498Szrj 	      error ("region of lp %i is wrong", lp->index);
346338fd1498Szrj 	      err = true;
346438fd1498Szrj 	    }
346538fd1498Szrj 	  nvisited_lp++;
346638fd1498Szrj 	}
346738fd1498Szrj 
346838fd1498Szrj       if (r->inner)
346938fd1498Szrj 	outer = r, r = r->inner, depth++;
347038fd1498Szrj       else if (r->next_peer)
347138fd1498Szrj 	r = r->next_peer;
347238fd1498Szrj       else
347338fd1498Szrj 	{
347438fd1498Szrj 	  do
347538fd1498Szrj 	    {
347638fd1498Szrj 	      r = r->outer;
347738fd1498Szrj 	      if (r == NULL)
347838fd1498Szrj 		goto region_done;
347938fd1498Szrj 	      depth--;
348038fd1498Szrj 	      outer = r->outer;
348138fd1498Szrj 	    }
348238fd1498Szrj 	  while (r->next_peer == NULL);
348338fd1498Szrj 	  r = r->next_peer;
348438fd1498Szrj 	}
348538fd1498Szrj     }
348638fd1498Szrj  region_done:
348738fd1498Szrj   if (depth != 0)
348838fd1498Szrj     {
348938fd1498Szrj       error ("tree list ends on depth %i", depth);
349038fd1498Szrj       err = true;
349138fd1498Szrj     }
349238fd1498Szrj   if (count_r != nvisited_r)
349338fd1498Szrj     {
349438fd1498Szrj       error ("region_array does not match region_tree");
349538fd1498Szrj       err = true;
349638fd1498Szrj     }
349738fd1498Szrj   if (count_lp != nvisited_lp)
349838fd1498Szrj     {
349938fd1498Szrj       error ("lp_array does not match region_tree");
350038fd1498Szrj       err = true;
350138fd1498Szrj     }
350238fd1498Szrj 
350338fd1498Szrj   if (err)
350438fd1498Szrj     {
350538fd1498Szrj       dump_eh_tree (stderr, fun);
350638fd1498Szrj       internal_error ("verify_eh_tree failed");
350738fd1498Szrj     }
350838fd1498Szrj }
350938fd1498Szrj 
351038fd1498Szrj #include "gt-except.h"
3511