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 (®ion->inner, r_reachable);
163638fd1498Szrj if (!bitmap_bit_p (r_reachable, region->index))
163738fd1498Szrj remove_eh_handler_splicer (pp);
163838fd1498Szrj else
163938fd1498Szrj pp = ®ion->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, ®ion, &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