150397Sobrien/* Implements exception handling. 290075Sobrien Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 3169689Skan 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. 450397Sobrien Contributed by Mike Stump <mrs@cygnus.com>. 550397Sobrien 690075SobrienThis file is part of GCC. 750397Sobrien 890075SobrienGCC is free software; you can redistribute it and/or modify it under 990075Sobrienthe terms of the GNU General Public License as published by the Free 1090075SobrienSoftware Foundation; either version 2, or (at your option) any later 1190075Sobrienversion. 1250397Sobrien 1390075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1490075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1590075SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1690075Sobrienfor more details. 1750397Sobrien 1850397SobrienYou should have received a copy of the GNU General Public License 1990075Sobrienalong with GCC; see the file COPYING. If not, write to the Free 20169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 21169689Skan02110-1301, USA. */ 2250397Sobrien 2350397Sobrien 2450397Sobrien/* An exception is an event that can be signaled from within a 2550397Sobrien function. This event can then be "caught" or "trapped" by the 2650397Sobrien callers of this function. This potentially allows program flow to 2750397Sobrien be transferred to any arbitrary code associated with a function call 2850397Sobrien several levels up the stack. 2950397Sobrien 3050397Sobrien The intended use for this mechanism is for signaling "exceptional 3150397Sobrien events" in an out-of-band fashion, hence its name. The C++ language 3250397Sobrien (and many other OO-styled or functional languages) practically 3350397Sobrien requires such a mechanism, as otherwise it becomes very difficult 3450397Sobrien or even impossible to signal failure conditions in complex 3550397Sobrien situations. The traditional C++ example is when an error occurs in 3650397Sobrien the process of constructing an object; without such a mechanism, it 3750397Sobrien is impossible to signal that the error occurs without adding global 3850397Sobrien state variables and error checks around every object construction. 3950397Sobrien 4050397Sobrien The act of causing this event to occur is referred to as "throwing 4150397Sobrien an exception". (Alternate terms include "raising an exception" or 4250397Sobrien "signaling an exception".) The term "throw" is used because control 4350397Sobrien is returned to the callers of the function that is signaling the 4450397Sobrien exception, and thus there is the concept of "throwing" the 4550397Sobrien exception up the call stack. 4650397Sobrien 4790075Sobrien [ Add updated documentation on how to use this. ] */ 4850397Sobrien 4950397Sobrien 5090075Sobrien#include "config.h" 5190075Sobrien#include "system.h" 52132718Skan#include "coretypes.h" 53132718Skan#include "tm.h" 5490075Sobrien#include "rtl.h" 5590075Sobrien#include "tree.h" 5690075Sobrien#include "flags.h" 5790075Sobrien#include "function.h" 5890075Sobrien#include "expr.h" 5990075Sobrien#include "libfuncs.h" 6090075Sobrien#include "insn-config.h" 6190075Sobrien#include "except.h" 6290075Sobrien#include "integrate.h" 6390075Sobrien#include "hard-reg-set.h" 6490075Sobrien#include "basic-block.h" 6590075Sobrien#include "output.h" 6690075Sobrien#include "dwarf2asm.h" 6790075Sobrien#include "dwarf2out.h" 6890075Sobrien#include "dwarf2.h" 6990075Sobrien#include "toplev.h" 7090075Sobrien#include "hashtab.h" 7190075Sobrien#include "intl.h" 7290075Sobrien#include "ggc.h" 7390075Sobrien#include "tm_p.h" 7490075Sobrien#include "target.h" 75117395Skan#include "langhooks.h" 76132718Skan#include "cgraph.h" 77169689Skan#include "diagnostic.h" 78169689Skan#include "tree-pass.h" 79169689Skan#include "timevar.h" 8050397Sobrien 8190075Sobrien/* Provide defaults for stuff that may not be defined when using 8290075Sobrien sjlj exceptions. */ 8390075Sobrien#ifndef EH_RETURN_DATA_REGNO 8490075Sobrien#define EH_RETURN_DATA_REGNO(N) INVALID_REGNUM 8590075Sobrien#endif 8650397Sobrien 8750397Sobrien 8890075Sobrien/* Protect cleanup actions with must-not-throw regions, with a call 8990075Sobrien to the given failure handler. */ 90132718Skantree (*lang_protect_cleanup_actions) (void); 9150397Sobrien 9290075Sobrien/* Return true if type A catches type B. */ 93132718Skanint (*lang_eh_type_covers) (tree a, tree b); 9450397Sobrien 9590075Sobrien/* Map a type to a runtime object to match type. */ 96132718Skantree (*lang_eh_runtime_type) (tree); 9750397Sobrien 9896263Sobrien/* A hash table of label to region number. */ 9950397Sobrien 100117395Skanstruct ehl_map_entry GTY(()) 10196263Sobrien{ 10296263Sobrien rtx label; 10396263Sobrien struct eh_region *region; 10496263Sobrien}; 10596263Sobrien 106132718Skanstatic GTY(()) int call_site_base; 107117395Skanstatic GTY ((param_is (union tree_node))) 108117395Skan htab_t type_to_runtime_map; 10950397Sobrien 11090075Sobrien/* Describe the SjLj_Function_Context structure. */ 111117395Skanstatic GTY(()) tree sjlj_fc_type_node; 11290075Sobrienstatic int sjlj_fc_call_site_ofs; 11390075Sobrienstatic int sjlj_fc_data_ofs; 11490075Sobrienstatic int sjlj_fc_personality_ofs; 11590075Sobrienstatic int sjlj_fc_lsda_ofs; 11690075Sobrienstatic int sjlj_fc_jbuf_ofs; 11790075Sobrien 11890075Sobrien/* Describes one exception region. */ 119117395Skanstruct eh_region GTY(()) 12090075Sobrien{ 12190075Sobrien /* The immediately surrounding region. */ 12290075Sobrien struct eh_region *outer; 12350397Sobrien 12490075Sobrien /* The list of immediately contained regions. */ 12590075Sobrien struct eh_region *inner; 12690075Sobrien struct eh_region *next_peer; 12750397Sobrien 12890075Sobrien /* An identifier for this region. */ 12990075Sobrien int region_number; 13050397Sobrien 13196263Sobrien /* When a region is deleted, its parents inherit the REG_EH_REGION 13296263Sobrien numbers already assigned. */ 13396263Sobrien bitmap aka; 13496263Sobrien 13590075Sobrien /* Each region does exactly one thing. */ 13690075Sobrien enum eh_region_type 13790075Sobrien { 13890075Sobrien ERT_UNKNOWN = 0, 13990075Sobrien ERT_CLEANUP, 14090075Sobrien ERT_TRY, 14190075Sobrien ERT_CATCH, 14290075Sobrien ERT_ALLOWED_EXCEPTIONS, 14390075Sobrien ERT_MUST_NOT_THROW, 144169689Skan ERT_THROW 14590075Sobrien } type; 14650397Sobrien 14790075Sobrien /* Holds the action to perform based on the preceding type. */ 148117395Skan union eh_region_u { 14990075Sobrien /* A list of catch blocks, a surrounding try block, 15090075Sobrien and the label for continuing after a catch. */ 151117395Skan struct eh_region_u_try { 15290075Sobrien struct eh_region *catch; 15390075Sobrien struct eh_region *last_catch; 154117395Skan } GTY ((tag ("ERT_TRY"))) try; 15550397Sobrien 15690075Sobrien /* The list through the catch handlers, the list of type objects 15790075Sobrien matched, and the list of associated filters. */ 158117395Skan struct eh_region_u_catch { 15990075Sobrien struct eh_region *next_catch; 16090075Sobrien struct eh_region *prev_catch; 16190075Sobrien tree type_list; 16290075Sobrien tree filter_list; 163117395Skan } GTY ((tag ("ERT_CATCH"))) catch; 16450397Sobrien 16590075Sobrien /* A tree_list of allowed types. */ 166117395Skan struct eh_region_u_allowed { 16790075Sobrien tree type_list; 16890075Sobrien int filter; 169117395Skan } GTY ((tag ("ERT_ALLOWED_EXCEPTIONS"))) allowed; 17050397Sobrien 17190075Sobrien /* The type given by a call to "throw foo();", or discovered 17290075Sobrien for a throw. */ 173117395Skan struct eh_region_u_throw { 17490075Sobrien tree type; 175117395Skan } GTY ((tag ("ERT_THROW"))) throw; 17650397Sobrien 17790075Sobrien /* Retain the cleanup expression even after expansion so that 17890075Sobrien we can match up fixup regions. */ 179117395Skan struct eh_region_u_cleanup { 180117395Skan struct eh_region *prev_try; 181117395Skan } GTY ((tag ("ERT_CLEANUP"))) cleanup; 182117395Skan } GTY ((desc ("%0.type"))) u; 18350397Sobrien 18490075Sobrien /* Entry point for this region's handler before landing pads are built. */ 18590075Sobrien rtx label; 186169689Skan tree tree_label; 18750397Sobrien 18890075Sobrien /* Entry point for this region's handler from the runtime eh library. */ 18990075Sobrien rtx landing_pad; 19050397Sobrien 19190075Sobrien /* Entry point for this region's handler from an inner region. */ 19290075Sobrien rtx post_landing_pad; 19350397Sobrien 19490075Sobrien /* The RESX insn for handing off control to the next outermost handler, 19590075Sobrien if appropriate. */ 19690075Sobrien rtx resume; 197117395Skan 198117395Skan /* True if something in this region may throw. */ 199117395Skan unsigned may_contain_throw : 1; 20090075Sobrien}; 20150397Sobrien 202169689Skantypedef struct eh_region *eh_region; 203169689Skan 204117395Skanstruct call_site_record GTY(()) 205117395Skan{ 206117395Skan rtx landing_pad; 207117395Skan int action; 208117395Skan}; 209117395Skan 210169689SkanDEF_VEC_P(eh_region); 211169689SkanDEF_VEC_ALLOC_P(eh_region, gc); 212169689Skan 21390075Sobrien/* Used to save exception status for each function. */ 214117395Skanstruct eh_status GTY(()) 21590075Sobrien{ 21690075Sobrien /* The tree of all regions for this function. */ 21790075Sobrien struct eh_region *region_tree; 21850397Sobrien 21990075Sobrien /* The same information as an indexable array. */ 220169689Skan VEC(eh_region,gc) *region_array; 22150397Sobrien 22290075Sobrien /* The most recently open region. */ 22390075Sobrien struct eh_region *cur_region; 22450397Sobrien 22590075Sobrien /* This is the region for which we are processing catch blocks. */ 22690075Sobrien struct eh_region *try_region; 22750397Sobrien 22890075Sobrien rtx filter; 22990075Sobrien rtx exc_ptr; 23050397Sobrien 23190075Sobrien int built_landing_pads; 23290075Sobrien int last_region_number; 23350397Sobrien 234169689Skan VEC(tree,gc) *ttype_data; 23590075Sobrien varray_type ehspec_data; 23690075Sobrien varray_type action_record_data; 23750397Sobrien 238117395Skan htab_t GTY ((param_is (struct ehl_map_entry))) exception_handler_label_map; 239117395Skan 240132718Skan struct call_site_record * GTY ((length ("%h.call_site_data_used"))) 241117395Skan call_site_data; 24290075Sobrien int call_site_data_used; 24390075Sobrien int call_site_data_size; 24450397Sobrien 24590075Sobrien rtx ehr_stackadj; 24690075Sobrien rtx ehr_handler; 24790075Sobrien rtx ehr_label; 24850397Sobrien 24990075Sobrien rtx sjlj_fc; 25090075Sobrien rtx sjlj_exit_after; 251169689Skan 252169689Skan htab_t GTY((param_is (struct throw_stmt_node))) throw_stmt_table; 25390075Sobrien}; 25490075Sobrien 255132718Skanstatic int t2r_eq (const void *, const void *); 256132718Skanstatic hashval_t t2r_hash (const void *); 257132718Skanstatic void add_type_for_runtime (tree); 258132718Skanstatic tree lookup_type_for_runtime (tree); 25950397Sobrien 260132718Skanstatic void remove_unreachable_regions (rtx); 26150397Sobrien 262132718Skanstatic int ttypes_filter_eq (const void *, const void *); 263132718Skanstatic hashval_t ttypes_filter_hash (const void *); 264132718Skanstatic int ehspec_filter_eq (const void *, const void *); 265132718Skanstatic hashval_t ehspec_filter_hash (const void *); 266132718Skanstatic int add_ttypes_entry (htab_t, tree); 267132718Skanstatic int add_ehspec_entry (htab_t, htab_t, tree); 268132718Skanstatic void assign_filter_values (void); 269132718Skanstatic void build_post_landing_pads (void); 270132718Skanstatic void connect_post_landing_pads (void); 271132718Skanstatic void dw2_build_landing_pads (void); 27250397Sobrien 27390075Sobrienstruct sjlj_lp_info; 274132718Skanstatic bool sjlj_find_directly_reachable_regions (struct sjlj_lp_info *); 275132718Skanstatic void sjlj_assign_call_site_values (rtx, struct sjlj_lp_info *); 276132718Skanstatic void sjlj_mark_call_sites (struct sjlj_lp_info *); 277132718Skanstatic void sjlj_emit_function_enter (rtx); 278132718Skanstatic void sjlj_emit_function_exit (void); 279132718Skanstatic void sjlj_emit_dispatch_table (rtx, struct sjlj_lp_info *); 280132718Skanstatic void sjlj_build_landing_pads (void); 28150397Sobrien 282132718Skanstatic hashval_t ehl_hash (const void *); 283132718Skanstatic int ehl_eq (const void *, const void *); 284132718Skanstatic void add_ehl_entry (rtx, struct eh_region *); 285132718Skanstatic void remove_exception_handler_label (rtx); 286132718Skanstatic void remove_eh_handler (struct eh_region *); 287132718Skanstatic int for_each_eh_label_1 (void **, void *); 28850397Sobrien 28990075Sobrien/* The return value of reachable_next_level. */ 29090075Sobrienenum reachable_code 29190075Sobrien{ 29290075Sobrien /* The given exception is not processed by the given region. */ 29390075Sobrien RNL_NOT_CAUGHT, 29490075Sobrien /* The given exception may need processing by the given region. */ 29590075Sobrien RNL_MAYBE_CAUGHT, 29690075Sobrien /* The given exception is completely processed by the given region. */ 29790075Sobrien RNL_CAUGHT, 29890075Sobrien /* The given exception is completely processed by the runtime. */ 29990075Sobrien RNL_BLOCKED 30090075Sobrien}; 30150397Sobrien 302169689Skanstruct reachable_info; 303132718Skanstatic enum reachable_code reachable_next_level (struct eh_region *, tree, 304132718Skan struct reachable_info *); 30550397Sobrien 306132718Skanstatic int action_record_eq (const void *, const void *); 307132718Skanstatic hashval_t action_record_hash (const void *); 308132718Skanstatic int add_action_record (htab_t, int, int); 309132718Skanstatic int collect_one_action_chain (htab_t, struct eh_region *); 310132718Skanstatic int add_call_site (rtx, int); 31150397Sobrien 312132718Skanstatic void push_uleb128 (varray_type *, unsigned int); 313132718Skanstatic void push_sleb128 (varray_type *, int); 31490075Sobrien#ifndef HAVE_AS_LEB128 315132718Skanstatic int dw2_size_of_call_site_table (void); 316132718Skanstatic int sjlj_size_of_call_site_table (void); 31790075Sobrien#endif 318132718Skanstatic void dw2_output_call_site_table (void); 319132718Skanstatic void sjlj_output_call_site_table (void); 32050397Sobrien 32190075Sobrien 32290075Sobrien/* Routine to see if exception handling is turned on. 323117395Skan DO_WARN is nonzero if we want to inform the user that exception 32490075Sobrien handling is turned off. 32550397Sobrien 32690075Sobrien This is used to ensure that -fexceptions has been specified if the 32790075Sobrien compiler tries to use any exception-specific functions. */ 32850397Sobrien 32990075Sobrienint 330132718Skandoing_eh (int do_warn) 33190075Sobrien{ 33290075Sobrien if (! flag_exceptions) 33390075Sobrien { 33490075Sobrien static int warned = 0; 33590075Sobrien if (! warned && do_warn) 33690075Sobrien { 33790075Sobrien error ("exception handling disabled, use -fexceptions to enable"); 33890075Sobrien warned = 1; 33990075Sobrien } 34090075Sobrien return 0; 34190075Sobrien } 34290075Sobrien return 1; 34390075Sobrien} 34450397Sobrien 34590075Sobrien 34690075Sobrienvoid 347132718Skaninit_eh (void) 34890075Sobrien{ 34990075Sobrien if (! flag_exceptions) 35090075Sobrien return; 35150397Sobrien 352117395Skan type_to_runtime_map = htab_create_ggc (31, t2r_hash, t2r_eq, NULL); 35350397Sobrien 35490075Sobrien /* Create the SjLj_Function_Context structure. This should match 35590075Sobrien the definition in unwind-sjlj.c. */ 35690075Sobrien if (USING_SJLJ_EXCEPTIONS) 35790075Sobrien { 35890075Sobrien tree f_jbuf, f_per, f_lsda, f_prev, f_cs, f_data, tmp; 35950397Sobrien 360169689Skan sjlj_fc_type_node = lang_hooks.types.make_type (RECORD_TYPE); 36150397Sobrien 36290075Sobrien f_prev = build_decl (FIELD_DECL, get_identifier ("__prev"), 36390075Sobrien build_pointer_type (sjlj_fc_type_node)); 36490075Sobrien DECL_FIELD_CONTEXT (f_prev) = sjlj_fc_type_node; 36550397Sobrien 36690075Sobrien f_cs = build_decl (FIELD_DECL, get_identifier ("__call_site"), 36790075Sobrien integer_type_node); 36890075Sobrien DECL_FIELD_CONTEXT (f_cs) = sjlj_fc_type_node; 36950397Sobrien 370169689Skan tmp = build_index_type (build_int_cst (NULL_TREE, 4 - 1)); 371169689Skan tmp = build_array_type (lang_hooks.types.type_for_mode (word_mode, 1), 372117395Skan tmp); 37390075Sobrien f_data = build_decl (FIELD_DECL, get_identifier ("__data"), tmp); 37490075Sobrien DECL_FIELD_CONTEXT (f_data) = sjlj_fc_type_node; 37550397Sobrien 37690075Sobrien f_per = build_decl (FIELD_DECL, get_identifier ("__personality"), 37790075Sobrien ptr_type_node); 37890075Sobrien DECL_FIELD_CONTEXT (f_per) = sjlj_fc_type_node; 37950397Sobrien 38090075Sobrien f_lsda = build_decl (FIELD_DECL, get_identifier ("__lsda"), 38190075Sobrien ptr_type_node); 38290075Sobrien DECL_FIELD_CONTEXT (f_lsda) = sjlj_fc_type_node; 38350397Sobrien 38490075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP 38590075Sobrien#ifdef JMP_BUF_SIZE 386169689Skan tmp = build_int_cst (NULL_TREE, JMP_BUF_SIZE - 1); 38790075Sobrien#else 38890075Sobrien /* Should be large enough for most systems, if it is not, 38990075Sobrien JMP_BUF_SIZE should be defined with the proper value. It will 39090075Sobrien also tend to be larger than necessary for most systems, a more 39190075Sobrien optimal port will define JMP_BUF_SIZE. */ 392169689Skan tmp = build_int_cst (NULL_TREE, FIRST_PSEUDO_REGISTER + 2 - 1); 39390075Sobrien#endif 39490075Sobrien#else 395132718Skan /* builtin_setjmp takes a pointer to 5 words. */ 396169689Skan tmp = build_int_cst (NULL_TREE, 5 * BITS_PER_WORD / POINTER_SIZE - 1); 39790075Sobrien#endif 39890075Sobrien tmp = build_index_type (tmp); 39990075Sobrien tmp = build_array_type (ptr_type_node, tmp); 40090075Sobrien f_jbuf = build_decl (FIELD_DECL, get_identifier ("__jbuf"), tmp); 40190075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP 40290075Sobrien /* We don't know what the alignment requirements of the 40390075Sobrien runtime's jmp_buf has. Overestimate. */ 40490075Sobrien DECL_ALIGN (f_jbuf) = BIGGEST_ALIGNMENT; 40590075Sobrien DECL_USER_ALIGN (f_jbuf) = 1; 40690075Sobrien#endif 40790075Sobrien DECL_FIELD_CONTEXT (f_jbuf) = sjlj_fc_type_node; 40850397Sobrien 40990075Sobrien TYPE_FIELDS (sjlj_fc_type_node) = f_prev; 41090075Sobrien TREE_CHAIN (f_prev) = f_cs; 41190075Sobrien TREE_CHAIN (f_cs) = f_data; 41290075Sobrien TREE_CHAIN (f_data) = f_per; 41390075Sobrien TREE_CHAIN (f_per) = f_lsda; 41490075Sobrien TREE_CHAIN (f_lsda) = f_jbuf; 41550397Sobrien 41690075Sobrien layout_type (sjlj_fc_type_node); 41750397Sobrien 41890075Sobrien /* Cache the interesting field offsets so that we have 41990075Sobrien easy access from rtl. */ 42090075Sobrien sjlj_fc_call_site_ofs 42190075Sobrien = (tree_low_cst (DECL_FIELD_OFFSET (f_cs), 1) 42290075Sobrien + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_cs), 1) / BITS_PER_UNIT); 42390075Sobrien sjlj_fc_data_ofs 42490075Sobrien = (tree_low_cst (DECL_FIELD_OFFSET (f_data), 1) 42590075Sobrien + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_data), 1) / BITS_PER_UNIT); 42690075Sobrien sjlj_fc_personality_ofs 42790075Sobrien = (tree_low_cst (DECL_FIELD_OFFSET (f_per), 1) 42890075Sobrien + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_per), 1) / BITS_PER_UNIT); 42990075Sobrien sjlj_fc_lsda_ofs 43090075Sobrien = (tree_low_cst (DECL_FIELD_OFFSET (f_lsda), 1) 43190075Sobrien + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_lsda), 1) / BITS_PER_UNIT); 43290075Sobrien sjlj_fc_jbuf_ofs 43390075Sobrien = (tree_low_cst (DECL_FIELD_OFFSET (f_jbuf), 1) 43490075Sobrien + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_jbuf), 1) / BITS_PER_UNIT); 43590075Sobrien } 43690075Sobrien} 43750397Sobrien 43890075Sobrienvoid 439132718Skaninit_eh_for_function (void) 44090075Sobrien{ 441132718Skan cfun->eh = ggc_alloc_cleared (sizeof (struct eh_status)); 44290075Sobrien} 44390075Sobrien 444169689Skan/* Routines to generate the exception tree somewhat directly. 445169689Skan These are used from tree-eh.c when processing exception related 446169689Skan nodes during tree optimization. */ 44750397Sobrien 448169689Skanstatic struct eh_region * 449169689Skangen_eh_region (enum eh_region_type type, struct eh_region *outer) 45090075Sobrien{ 451169689Skan struct eh_region *new; 45252284Sobrien 453169689Skan#ifdef ENABLE_CHECKING 454169689Skan gcc_assert (doing_eh (0)); 455169689Skan#endif 45652284Sobrien 45790075Sobrien /* Insert a new blank region as a leaf in the tree. */ 458169689Skan new = ggc_alloc_cleared (sizeof (*new)); 459169689Skan new->type = type; 460169689Skan new->outer = outer; 461169689Skan if (outer) 46290075Sobrien { 463169689Skan new->next_peer = outer->inner; 464169689Skan outer->inner = new; 46590075Sobrien } 46690075Sobrien else 46790075Sobrien { 468169689Skan new->next_peer = cfun->eh->region_tree; 469169689Skan cfun->eh->region_tree = new; 47090075Sobrien } 47152284Sobrien 472169689Skan new->region_number = ++cfun->eh->last_region_number; 47352284Sobrien 474169689Skan return new; 47590075Sobrien} 47650397Sobrien 477169689Skanstruct eh_region * 478169689Skangen_eh_region_cleanup (struct eh_region *outer, struct eh_region *prev_try) 47952284Sobrien{ 480169689Skan struct eh_region *cleanup = gen_eh_region (ERT_CLEANUP, outer); 481169689Skan cleanup->u.cleanup.prev_try = prev_try; 482169689Skan return cleanup; 48350397Sobrien} 48450397Sobrien 485169689Skanstruct eh_region * 486169689Skangen_eh_region_try (struct eh_region *outer) 48750397Sobrien{ 488169689Skan return gen_eh_region (ERT_TRY, outer); 48950397Sobrien} 49050397Sobrien 491169689Skanstruct eh_region * 492169689Skangen_eh_region_catch (struct eh_region *t, tree type_or_list) 49350397Sobrien{ 494169689Skan struct eh_region *c, *l; 495169689Skan tree type_list, type_node; 49650397Sobrien 497169689Skan /* Ensure to always end up with a type list to normalize further 498169689Skan processing, then register each type against the runtime types map. */ 49990075Sobrien type_list = type_or_list; 50090075Sobrien if (type_or_list) 50190075Sobrien { 50290075Sobrien if (TREE_CODE (type_or_list) != TREE_LIST) 503117395Skan type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE); 50490075Sobrien 50590075Sobrien type_node = type_list; 50690075Sobrien for (; type_node; type_node = TREE_CHAIN (type_node)) 507117395Skan add_type_for_runtime (TREE_VALUE (type_node)); 50890075Sobrien } 50990075Sobrien 510169689Skan c = gen_eh_region (ERT_CATCH, t->outer); 51190075Sobrien c->u.catch.type_list = type_list; 51290075Sobrien l = t->u.try.last_catch; 51390075Sobrien c->u.catch.prev_catch = l; 51490075Sobrien if (l) 51590075Sobrien l->u.catch.next_catch = c; 51652284Sobrien else 51790075Sobrien t->u.try.catch = c; 51890075Sobrien t->u.try.last_catch = c; 51950397Sobrien 520169689Skan return c; 52150397Sobrien} 52250397Sobrien 523169689Skanstruct eh_region * 524169689Skangen_eh_region_allowed (struct eh_region *outer, tree allowed) 52550397Sobrien{ 526169689Skan struct eh_region *region = gen_eh_region (ERT_ALLOWED_EXCEPTIONS, outer); 527169689Skan region->u.allowed.type_list = allowed; 52850397Sobrien 529169689Skan for (; allowed ; allowed = TREE_CHAIN (allowed)) 530169689Skan add_type_for_runtime (TREE_VALUE (allowed)); 53150397Sobrien 532169689Skan return region; 533169689Skan} 53450397Sobrien 535169689Skanstruct eh_region * 536169689Skangen_eh_region_must_not_throw (struct eh_region *outer) 537169689Skan{ 538169689Skan return gen_eh_region (ERT_MUST_NOT_THROW, outer); 53950397Sobrien} 54050397Sobrien 541169689Skanint 542169689Skanget_eh_region_number (struct eh_region *region) 54350397Sobrien{ 544169689Skan return region->region_number; 54550397Sobrien} 54650397Sobrien 547169689Skanbool 548169689Skanget_eh_region_may_contain_throw (struct eh_region *region) 54950397Sobrien{ 550169689Skan return region->may_contain_throw; 55150397Sobrien} 55250397Sobrien 553169689Skantree 554169689Skanget_eh_region_tree_label (struct eh_region *region) 55550397Sobrien{ 556169689Skan return region->tree_label; 55750397Sobrien} 55850397Sobrien 55990075Sobrienvoid 560169689Skanset_eh_region_tree_label (struct eh_region *region, tree lab) 56150397Sobrien{ 562169689Skan region->tree_label = lab; 56390075Sobrien} 564169689Skan 56590075Sobrienvoid 566169689Skanexpand_resx_expr (tree exp) 56750397Sobrien{ 568169689Skan int region_nr = TREE_INT_CST_LOW (TREE_OPERAND (exp, 0)); 569169689Skan struct eh_region *reg = VEC_index (eh_region, 570169689Skan cfun->eh->region_array, region_nr); 57150397Sobrien 572169689Skan gcc_assert (!reg->resume); 573169689Skan reg->resume = emit_jump_insn (gen_rtx_RESX (VOIDmode, region_nr)); 574169689Skan emit_barrier (); 57550397Sobrien} 57650397Sobrien 577117395Skan/* Note that the current EH region (if any) may contain a throw, or a 578117395Skan call to a function which itself may contain a throw. */ 579117395Skan 580117395Skanvoid 581169689Skannote_eh_region_may_contain_throw (struct eh_region *region) 582117395Skan{ 583117395Skan while (region && !region->may_contain_throw) 584117395Skan { 585117395Skan region->may_contain_throw = 1; 586117395Skan region = region->outer; 587117395Skan } 588117395Skan} 589117395Skan 590169689Skanvoid 591169689Skannote_current_region_may_contain_throw (void) 592169689Skan{ 593169689Skan note_eh_region_may_contain_throw (cfun->eh->cur_region); 594169689Skan} 595169689Skan 596169689Skan 59790075Sobrien/* Return an rtl expression for a pointer to the exception object 59890075Sobrien within a handler. */ 59950397Sobrien 60090075Sobrienrtx 601132718Skanget_exception_pointer (struct function *fun) 60250397Sobrien{ 60390075Sobrien rtx exc_ptr = fun->eh->exc_ptr; 60490075Sobrien if (fun == cfun && ! exc_ptr) 60550397Sobrien { 606117395Skan exc_ptr = gen_reg_rtx (ptr_mode); 60790075Sobrien fun->eh->exc_ptr = exc_ptr; 60850397Sobrien } 60990075Sobrien return exc_ptr; 61050397Sobrien} 61150397Sobrien 61290075Sobrien/* Return an rtl expression for the exception dispatch filter 61390075Sobrien within a handler. */ 61450397Sobrien 615169689Skanrtx 616132718Skanget_exception_filter (struct function *fun) 61750397Sobrien{ 61890075Sobrien rtx filter = fun->eh->filter; 61990075Sobrien if (fun == cfun && ! filter) 62050397Sobrien { 621169689Skan filter = gen_reg_rtx (targetm.eh_return_filter_mode ()); 62290075Sobrien fun->eh->filter = filter; 62350397Sobrien } 62490075Sobrien return filter; 62550397Sobrien} 62690075Sobrien 62790075Sobrien/* This section is for the exception handling specific optimization pass. */ 62850397Sobrien 629169689Skan/* Random access the exception region tree. */ 63090075Sobrien 631169689Skanvoid 632132718Skancollect_eh_region_array (void) 63350397Sobrien{ 634169689Skan struct eh_region *i; 63550397Sobrien 63690075Sobrien i = cfun->eh->region_tree; 63790075Sobrien if (! i) 63890075Sobrien return; 63950397Sobrien 640169689Skan VEC_safe_grow (eh_region, gc, cfun->eh->region_array, 641169689Skan cfun->eh->last_region_number + 1); 642169689Skan VEC_replace (eh_region, cfun->eh->region_array, 0, 0); 64350397Sobrien 64490075Sobrien while (1) 64590075Sobrien { 646169689Skan VEC_replace (eh_region, cfun->eh->region_array, i->region_number, i); 64750397Sobrien 64890075Sobrien /* If there are sub-regions, process them. */ 64990075Sobrien if (i->inner) 65090075Sobrien i = i->inner; 65190075Sobrien /* If there are peers, process them. */ 65290075Sobrien else if (i->next_peer) 65390075Sobrien i = i->next_peer; 65490075Sobrien /* Otherwise, step back up the tree to the next peer. */ 65590075Sobrien else 65690075Sobrien { 65790075Sobrien do { 65890075Sobrien i = i->outer; 65990075Sobrien if (i == NULL) 66090075Sobrien return; 66190075Sobrien } while (i->next_peer == NULL); 66290075Sobrien i = i->next_peer; 66390075Sobrien } 66490075Sobrien } 66590075Sobrien} 66650397Sobrien 66790075Sobrien/* Remove all regions whose labels are not reachable from insns. */ 66852284Sobrien 66990075Sobrienstatic void 670132718Skanremove_unreachable_regions (rtx insns) 67152284Sobrien{ 67290075Sobrien int i, *uid_region_num; 67390075Sobrien bool *reachable; 67490075Sobrien struct eh_region *r; 67590075Sobrien rtx insn; 67652284Sobrien 67790075Sobrien uid_region_num = xcalloc (get_max_uid (), sizeof(int)); 67890075Sobrien reachable = xcalloc (cfun->eh->last_region_number + 1, sizeof(bool)); 67952284Sobrien 68090075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 68190075Sobrien { 682169689Skan r = VEC_index (eh_region, cfun->eh->region_array, i); 68390075Sobrien if (!r || r->region_number != i) 68490075Sobrien continue; 68552284Sobrien 68690075Sobrien if (r->resume) 687117395Skan { 688169689Skan gcc_assert (!uid_region_num[INSN_UID (r->resume)]); 68990075Sobrien uid_region_num[INSN_UID (r->resume)] = i; 690117395Skan } 69190075Sobrien if (r->label) 692117395Skan { 693169689Skan gcc_assert (!uid_region_num[INSN_UID (r->label)]); 69490075Sobrien uid_region_num[INSN_UID (r->label)] = i; 695117395Skan } 69652284Sobrien } 69752284Sobrien 69890075Sobrien for (insn = insns; insn; insn = NEXT_INSN (insn)) 699169689Skan reachable[uid_region_num[INSN_UID (insn)]] = true; 70050397Sobrien 70190075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 70250397Sobrien { 703169689Skan r = VEC_index (eh_region, cfun->eh->region_array, i); 70490075Sobrien if (r && r->region_number == i && !reachable[i]) 70550397Sobrien { 706169689Skan bool kill_it = true; 707169689Skan switch (r->type) 70890075Sobrien { 709169689Skan case ERT_THROW: 710169689Skan /* Don't remove ERT_THROW regions if their outer region 711169689Skan is reachable. */ 712169689Skan if (r->outer && reachable[r->outer->region_number]) 713169689Skan kill_it = false; 714169689Skan break; 71550397Sobrien 716169689Skan case ERT_MUST_NOT_THROW: 717169689Skan /* MUST_NOT_THROW regions are implementable solely in the 718169689Skan runtime, but their existence continues to affect calls 719169689Skan within that region. Never delete them here. */ 720169689Skan kill_it = false; 721169689Skan break; 72250397Sobrien 723169689Skan case ERT_TRY: 724169689Skan { 725169689Skan /* TRY regions are reachable if any of its CATCH regions 726169689Skan are reachable. */ 727169689Skan struct eh_region *c; 728169689Skan for (c = r->u.try.catch; c ; c = c->u.catch.next_catch) 729169689Skan if (reachable[c->region_number]) 73090075Sobrien { 731169689Skan kill_it = false; 732169689Skan break; 73390075Sobrien } 734169689Skan break; 735169689Skan } 73650397Sobrien 737169689Skan default: 738169689Skan break; 73990075Sobrien } 74050397Sobrien 741169689Skan if (kill_it) 742169689Skan remove_eh_handler (r); 74390075Sobrien } 74490075Sobrien } 74550397Sobrien 746169689Skan free (reachable); 747169689Skan free (uid_region_num); 74850397Sobrien} 74950397Sobrien 750169689Skan/* Set up EH labels for RTL. */ 751169689Skan 75290075Sobrienvoid 753132718Skanconvert_from_eh_region_ranges (void) 75450397Sobrien{ 755169689Skan rtx insns = get_insns (); 756169689Skan int i, n = cfun->eh->last_region_number; 75750397Sobrien 758169689Skan /* Most of the work is already done at the tree level. All we need to 759169689Skan do is collect the rtl labels that correspond to the tree labels that 760169689Skan collect the rtl labels that correspond to the tree labels 761169689Skan we allocated earlier. */ 762169689Skan for (i = 1; i <= n; ++i) 763169689Skan { 764169689Skan struct eh_region *region; 76550397Sobrien 766169689Skan region = VEC_index (eh_region, cfun->eh->region_array, i); 767169689Skan if (region && region->tree_label) 768169689Skan region->label = DECL_RTL_IF_SET (region->tree_label); 769169689Skan } 77050397Sobrien 77190075Sobrien remove_unreachable_regions (insns); 77250397Sobrien} 77350397Sobrien 77496263Sobrienstatic void 775132718Skanadd_ehl_entry (rtx label, struct eh_region *region) 77696263Sobrien{ 77796263Sobrien struct ehl_map_entry **slot, *entry; 77896263Sobrien 77996263Sobrien LABEL_PRESERVE_P (label) = 1; 78096263Sobrien 781132718Skan entry = ggc_alloc (sizeof (*entry)); 78296263Sobrien entry->label = label; 78396263Sobrien entry->region = region; 78496263Sobrien 78596263Sobrien slot = (struct ehl_map_entry **) 786117395Skan htab_find_slot (cfun->eh->exception_handler_label_map, entry, INSERT); 78796263Sobrien 78896263Sobrien /* Before landing pad creation, each exception handler has its own 78996263Sobrien label. After landing pad creation, the exception handlers may 79096263Sobrien share landing pads. This is ok, since maybe_remove_eh_handler 79196263Sobrien only requires the 1-1 mapping before landing pad creation. */ 792169689Skan gcc_assert (!*slot || cfun->eh->built_landing_pads); 79396263Sobrien 79496263Sobrien *slot = entry; 79596263Sobrien} 79696263Sobrien 79790075Sobrienvoid 798132718Skanfind_exception_handler_labels (void) 79990075Sobrien{ 80090075Sobrien int i; 80150397Sobrien 802117395Skan if (cfun->eh->exception_handler_label_map) 803117395Skan htab_empty (cfun->eh->exception_handler_label_map); 80496263Sobrien else 80596263Sobrien { 80696263Sobrien /* ??? The expansion factor here (3/2) must be greater than the htab 80796263Sobrien occupancy factor (4/3) to avoid unnecessary resizing. */ 808117395Skan cfun->eh->exception_handler_label_map 809117395Skan = htab_create_ggc (cfun->eh->last_region_number * 3 / 2, 810117395Skan ehl_hash, ehl_eq, NULL); 81196263Sobrien } 81250397Sobrien 81390075Sobrien if (cfun->eh->region_tree == NULL) 81490075Sobrien return; 81590075Sobrien 81690075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 81750397Sobrien { 818169689Skan struct eh_region *region; 81990075Sobrien rtx lab; 82050397Sobrien 821169689Skan region = VEC_index (eh_region, cfun->eh->region_array, i); 82290075Sobrien if (! region || region->region_number != i) 82390075Sobrien continue; 82490075Sobrien if (cfun->eh->built_landing_pads) 82590075Sobrien lab = region->landing_pad; 82690075Sobrien else 82790075Sobrien lab = region->label; 82850397Sobrien 82990075Sobrien if (lab) 83096263Sobrien add_ehl_entry (lab, region); 83150397Sobrien } 83290075Sobrien 83390075Sobrien /* For sjlj exceptions, need the return label to remain live until 83490075Sobrien after landing pad generation. */ 83590075Sobrien if (USING_SJLJ_EXCEPTIONS && ! cfun->eh->built_landing_pads) 83696263Sobrien add_ehl_entry (return_label, NULL); 83796263Sobrien} 83890075Sobrien 839169689Skan/* Returns true if the current function has exception handling regions. */ 840169689Skan 84196263Sobrienbool 842132718Skancurrent_function_has_exception_handlers (void) 84396263Sobrien{ 84496263Sobrien int i; 84596263Sobrien 84696263Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 84796263Sobrien { 848169689Skan struct eh_region *region; 84996263Sobrien 850169689Skan region = VEC_index (eh_region, cfun->eh->region_array, i); 851169689Skan if (region 852169689Skan && region->region_number == i 853169689Skan && region->type != ERT_THROW) 85496263Sobrien return true; 85596263Sobrien } 85696263Sobrien 85796263Sobrien return false; 85850397Sobrien} 85990075Sobrien 860169689Skan/* A subroutine of duplicate_eh_regions. Search the region tree under O 861169689Skan for the minimum and maximum region numbers. Update *MIN and *MAX. */ 862169689Skan 863169689Skanstatic void 864169689Skanduplicate_eh_regions_0 (eh_region o, int *min, int *max) 86550397Sobrien{ 866169689Skan if (o->region_number < *min) 867169689Skan *min = o->region_number; 868169689Skan if (o->region_number > *max) 869169689Skan *max = o->region_number; 87050397Sobrien 871169689Skan if (o->inner) 87290075Sobrien { 873169689Skan o = o->inner; 874169689Skan duplicate_eh_regions_0 (o, min, max); 875169689Skan while (o->next_peer) 876169689Skan { 877169689Skan o = o->next_peer; 878169689Skan duplicate_eh_regions_0 (o, min, max); 879169689Skan } 880169689Skan } 881169689Skan} 88250397Sobrien 883169689Skan/* A subroutine of duplicate_eh_regions. Copy the region tree under OLD. 884169689Skan Root it at OUTER, and apply EH_OFFSET to the region number. Don't worry 885169689Skan about the other internal pointers just yet, just the tree-like pointers. */ 88650397Sobrien 887169689Skanstatic eh_region 888169689Skanduplicate_eh_regions_1 (eh_region old, eh_region outer, int eh_offset) 889169689Skan{ 890169689Skan eh_region ret, n; 89150397Sobrien 892169689Skan ret = n = ggc_alloc (sizeof (struct eh_region)); 89350397Sobrien 894169689Skan *n = *old; 895169689Skan n->outer = outer; 896169689Skan n->next_peer = NULL; 897169689Skan gcc_assert (!old->aka); 89850397Sobrien 899169689Skan n->region_number += eh_offset; 900169689Skan VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n); 90150397Sobrien 902169689Skan if (old->inner) 90390075Sobrien { 904169689Skan old = old->inner; 905169689Skan n = n->inner = duplicate_eh_regions_1 (old, ret, eh_offset); 906169689Skan while (old->next_peer) 907169689Skan { 908169689Skan old = old->next_peer; 909169689Skan n = n->next_peer = duplicate_eh_regions_1 (old, ret, eh_offset); 910169689Skan } 91190075Sobrien } 91250397Sobrien 913169689Skan return ret; 91450397Sobrien} 91550397Sobrien 916169689Skan/* Duplicate the EH regions of IFUN, rooted at COPY_REGION, into current 917169689Skan function and root the tree below OUTER_REGION. Remap labels using MAP 918169689Skan callback. The special case of COPY_REGION of 0 means all regions. */ 919169689Skan 920169689Skanint 921169689Skanduplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map, 922169689Skan void *data, int copy_region, int outer_region) 92350397Sobrien{ 924169689Skan eh_region cur, prev_try, outer, *splice; 925169689Skan int i, min_region, max_region, eh_offset, cfun_last_region_number; 926169689Skan int num_regions; 92750397Sobrien 928169689Skan if (!ifun->eh->region_tree) 929169689Skan return 0; 930169689Skan 931169689Skan /* Find the range of region numbers to be copied. The interface we 932169689Skan provide here mandates a single offset to find new number from old, 933169689Skan which means we must look at the numbers present, instead of the 934169689Skan count or something else. */ 935169689Skan if (copy_region > 0) 93690075Sobrien { 937169689Skan min_region = INT_MAX; 938169689Skan max_region = 0; 93950397Sobrien 940169689Skan cur = VEC_index (eh_region, ifun->eh->region_array, copy_region); 941169689Skan duplicate_eh_regions_0 (cur, &min_region, &max_region); 94290075Sobrien } 943169689Skan else 944169689Skan min_region = 1, max_region = ifun->eh->last_region_number; 945169689Skan num_regions = max_region - min_region + 1; 946169689Skan cfun_last_region_number = cfun->eh->last_region_number; 947169689Skan eh_offset = cfun_last_region_number + 1 - min_region; 94890075Sobrien 949169689Skan /* If we've not yet created a region array, do so now. */ 950169689Skan VEC_safe_grow (eh_region, gc, cfun->eh->region_array, 951169689Skan cfun_last_region_number + 1 + num_regions); 952169689Skan cfun->eh->last_region_number = max_region + eh_offset; 95390075Sobrien 954169689Skan /* We may have just allocated the array for the first time. 955169689Skan Make sure that element zero is null. */ 956169689Skan VEC_replace (eh_region, cfun->eh->region_array, 0, 0); 95750397Sobrien 958169689Skan /* Zero all entries in the range allocated. */ 959169689Skan memset (VEC_address (eh_region, cfun->eh->region_array) 960169689Skan + cfun_last_region_number + 1, 0, num_regions * sizeof (eh_region)); 96150397Sobrien 962169689Skan /* Locate the spot at which to insert the new tree. */ 963169689Skan if (outer_region > 0) 964169689Skan { 965169689Skan outer = VEC_index (eh_region, cfun->eh->region_array, outer_region); 966169689Skan splice = &outer->inner; 967169689Skan } 968169689Skan else 969169689Skan { 970169689Skan outer = NULL; 971169689Skan splice = &cfun->eh->region_tree; 972169689Skan } 973169689Skan while (*splice) 974169689Skan splice = &(*splice)->next_peer; 97550397Sobrien 976169689Skan /* Copy all the regions in the subtree. */ 977169689Skan if (copy_region > 0) 97890075Sobrien { 979169689Skan cur = VEC_index (eh_region, ifun->eh->region_array, copy_region); 980169689Skan *splice = duplicate_eh_regions_1 (cur, outer, eh_offset); 98190075Sobrien } 982169689Skan else 98390075Sobrien { 984169689Skan eh_region n; 985169689Skan 986169689Skan cur = ifun->eh->region_tree; 987169689Skan *splice = n = duplicate_eh_regions_1 (cur, outer, eh_offset); 988169689Skan while (cur->next_peer) 989169689Skan { 990169689Skan cur = cur->next_peer; 991169689Skan n = n->next_peer = duplicate_eh_regions_1 (cur, outer, eh_offset); 992169689Skan } 99390075Sobrien } 99450397Sobrien 995169689Skan /* Remap all the labels in the new regions. */ 996169689Skan for (i = cfun_last_region_number + 1; 997169689Skan VEC_iterate (eh_region, cfun->eh->region_array, i, cur); ++i) 998169689Skan if (cur && cur->tree_label) 999169689Skan cur->tree_label = map (cur->tree_label, data); 1000169689Skan 1001169689Skan /* Search for the containing ERT_TRY region to fix up 1002169689Skan the prev_try short-cuts for ERT_CLEANUP regions. */ 1003169689Skan prev_try = NULL; 1004169689Skan if (outer_region > 0) 1005169689Skan for (prev_try = VEC_index (eh_region, cfun->eh->region_array, outer_region); 1006169689Skan prev_try && prev_try->type != ERT_TRY; 1007169689Skan prev_try = prev_try->outer) 1008171825Skan if (prev_try->type == ERT_MUST_NOT_THROW) 1009171825Skan { 1010171825Skan prev_try = NULL; 1011171825Skan break; 1012171825Skan } 1013169689Skan 1014169689Skan /* Remap all of the internal catch and cleanup linkages. Since we 1015169689Skan duplicate entire subtrees, all of the referenced regions will have 1016169689Skan been copied too. And since we renumbered them as a block, a simple 1017169689Skan bit of arithmetic finds us the index for the replacement region. */ 1018169689Skan for (i = cfun_last_region_number + 1; 1019169689Skan VEC_iterate (eh_region, cfun->eh->region_array, i, cur); ++i) 102090075Sobrien { 1021169689Skan if (cur == NULL) 1022169689Skan continue; 1023169689Skan 1024169689Skan#define REMAP(REG) \ 1025169689Skan (REG) = VEC_index (eh_region, cfun->eh->region_array, \ 1026169689Skan (REG)->region_number + eh_offset) 1027169689Skan 1028169689Skan switch (cur->type) 102990075Sobrien { 1030169689Skan case ERT_TRY: 1031169689Skan if (cur->u.try.catch) 1032169689Skan REMAP (cur->u.try.catch); 1033169689Skan if (cur->u.try.last_catch) 1034169689Skan REMAP (cur->u.try.last_catch); 1035169689Skan break; 1036169689Skan 1037169689Skan case ERT_CATCH: 1038169689Skan if (cur->u.catch.next_catch) 1039169689Skan REMAP (cur->u.catch.next_catch); 1040169689Skan if (cur->u.catch.prev_catch) 1041169689Skan REMAP (cur->u.catch.prev_catch); 1042169689Skan break; 1043169689Skan 1044169689Skan case ERT_CLEANUP: 1045169689Skan if (cur->u.cleanup.prev_try) 1046169689Skan REMAP (cur->u.cleanup.prev_try); 1047169689Skan else 1048169689Skan cur->u.cleanup.prev_try = prev_try; 1049169689Skan break; 1050169689Skan 1051169689Skan default: 1052169689Skan break; 105390075Sobrien } 105450397Sobrien 1055169689Skan#undef REMAP 105690075Sobrien } 1057169689Skan 1058169689Skan return eh_offset; 1059169689Skan} 1060169689Skan 1061169689Skan/* Return true if REGION_A is outer to REGION_B in IFUN. */ 1062169689Skan 1063169689Skanbool 1064169689Skaneh_region_outer_p (struct function *ifun, int region_a, int region_b) 1065169689Skan{ 1066169689Skan struct eh_region *rp_a, *rp_b; 1067169689Skan 1068169689Skan gcc_assert (ifun->eh->last_region_number > 0); 1069169689Skan gcc_assert (ifun->eh->region_tree); 1070169689Skan 1071169689Skan rp_a = VEC_index (eh_region, ifun->eh->region_array, region_a); 1072169689Skan rp_b = VEC_index (eh_region, ifun->eh->region_array, region_b); 1073169689Skan gcc_assert (rp_a != NULL); 1074169689Skan gcc_assert (rp_b != NULL); 1075169689Skan 1076169689Skan do 107790075Sobrien { 1078169689Skan if (rp_a == rp_b) 1079169689Skan return true; 1080169689Skan rp_b = rp_b->outer; 1081169689Skan } 1082169689Skan while (rp_b); 1083169689Skan 1084169689Skan return false; 1085169689Skan} 1086169689Skan 1087169689Skan/* Return region number of region that is outer to both if REGION_A and 1088169689Skan REGION_B in IFUN. */ 1089169689Skan 1090169689Skanint 1091169689Skaneh_region_outermost (struct function *ifun, int region_a, int region_b) 1092169689Skan{ 1093169689Skan struct eh_region *rp_a, *rp_b; 1094169689Skan sbitmap b_outer; 1095169689Skan 1096169689Skan gcc_assert (ifun->eh->last_region_number > 0); 1097169689Skan gcc_assert (ifun->eh->region_tree); 1098169689Skan 1099169689Skan rp_a = VEC_index (eh_region, ifun->eh->region_array, region_a); 1100169689Skan rp_b = VEC_index (eh_region, ifun->eh->region_array, region_b); 1101169689Skan gcc_assert (rp_a != NULL); 1102169689Skan gcc_assert (rp_b != NULL); 1103169689Skan 1104169689Skan b_outer = sbitmap_alloc (ifun->eh->last_region_number + 1); 1105169689Skan sbitmap_zero (b_outer); 1106169689Skan 1107169689Skan do 1108169689Skan { 1109169689Skan SET_BIT (b_outer, rp_b->region_number); 1110169689Skan rp_b = rp_b->outer; 1111169689Skan } 1112169689Skan while (rp_b); 1113169689Skan 1114169689Skan do 1115169689Skan { 1116169689Skan if (TEST_BIT (b_outer, rp_a->region_number)) 111790075Sobrien { 1118169689Skan sbitmap_free (b_outer); 1119169689Skan return rp_a->region_number; 112090075Sobrien } 1121169689Skan rp_a = rp_a->outer; 112290075Sobrien } 1123169689Skan while (rp_a); 112450397Sobrien 1125169689Skan sbitmap_free (b_outer); 1126169689Skan return -1; 112790075Sobrien} 112890075Sobrien 112990075Sobrienstatic int 1130132718Skant2r_eq (const void *pentry, const void *pdata) 113190075Sobrien{ 113290075Sobrien tree entry = (tree) pentry; 113390075Sobrien tree data = (tree) pdata; 113450397Sobrien 113590075Sobrien return TREE_PURPOSE (entry) == data; 113690075Sobrien} 113750397Sobrien 113890075Sobrienstatic hashval_t 1139132718Skant2r_hash (const void *pentry) 114090075Sobrien{ 114190075Sobrien tree entry = (tree) pentry; 1142169689Skan return TREE_HASH (TREE_PURPOSE (entry)); 114350397Sobrien} 114450397Sobrien 114550397Sobrienstatic void 1146132718Skanadd_type_for_runtime (tree type) 114790075Sobrien{ 114890075Sobrien tree *slot; 114950397Sobrien 115090075Sobrien slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type, 1151169689Skan TREE_HASH (type), INSERT); 115290075Sobrien if (*slot == NULL) 115390075Sobrien { 115490075Sobrien tree runtime = (*lang_eh_runtime_type) (type); 115590075Sobrien *slot = tree_cons (type, runtime, NULL_TREE); 115690075Sobrien } 115790075Sobrien} 115850397Sobrien 115990075Sobrienstatic tree 1160132718Skanlookup_type_for_runtime (tree type) 116190075Sobrien{ 116290075Sobrien tree *slot; 116350397Sobrien 116490075Sobrien slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type, 1165169689Skan TREE_HASH (type), NO_INSERT); 116650397Sobrien 116790075Sobrien /* We should have always inserted the data earlier. */ 116890075Sobrien return TREE_VALUE (*slot); 116990075Sobrien} 117050397Sobrien 117190075Sobrien 117290075Sobrien/* Represent an entry in @TTypes for either catch actions 117390075Sobrien or exception filter actions. */ 1174117395Skanstruct ttypes_filter GTY(()) 117590075Sobrien{ 117690075Sobrien tree t; 117790075Sobrien int filter; 117890075Sobrien}; 117950397Sobrien 118090075Sobrien/* Compare ENTRY (a ttypes_filter entry in the hash table) with DATA 118190075Sobrien (a tree) for a @TTypes type node we are thinking about adding. */ 118250397Sobrien 118390075Sobrienstatic int 1184132718Skanttypes_filter_eq (const void *pentry, const void *pdata) 118590075Sobrien{ 118690075Sobrien const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry; 118790075Sobrien tree data = (tree) pdata; 118850397Sobrien 118990075Sobrien return entry->t == data; 119050397Sobrien} 119150397Sobrien 119290075Sobrienstatic hashval_t 1193132718Skanttypes_filter_hash (const void *pentry) 119490075Sobrien{ 119590075Sobrien const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry; 1196169689Skan return TREE_HASH (entry->t); 119790075Sobrien} 119850397Sobrien 119990075Sobrien/* Compare ENTRY with DATA (both struct ttypes_filter) for a @TTypes 120090075Sobrien exception specification list we are thinking about adding. */ 120190075Sobrien/* ??? Currently we use the type lists in the order given. Someone 120290075Sobrien should put these in some canonical order. */ 120350397Sobrien 120490075Sobrienstatic int 1205132718Skanehspec_filter_eq (const void *pentry, const void *pdata) 120650397Sobrien{ 120790075Sobrien const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry; 120890075Sobrien const struct ttypes_filter *data = (const struct ttypes_filter *) pdata; 120950397Sobrien 121090075Sobrien return type_list_equal (entry->t, data->t); 121190075Sobrien} 121250397Sobrien 121390075Sobrien/* Hash function for exception specification lists. */ 121450397Sobrien 121590075Sobrienstatic hashval_t 1216132718Skanehspec_filter_hash (const void *pentry) 121790075Sobrien{ 121890075Sobrien const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry; 121990075Sobrien hashval_t h = 0; 122090075Sobrien tree list; 122150397Sobrien 122290075Sobrien for (list = entry->t; list ; list = TREE_CHAIN (list)) 1223169689Skan h = (h << 5) + (h >> 27) + TREE_HASH (TREE_VALUE (list)); 122490075Sobrien return h; 122550397Sobrien} 122650397Sobrien 1227169689Skan/* Add TYPE (which may be NULL) to cfun->eh->ttype_data, using TYPES_HASH 1228169689Skan to speed up the search. Return the filter value to be used. */ 122950397Sobrien 123090075Sobrienstatic int 1231132718Skanadd_ttypes_entry (htab_t ttypes_hash, tree type) 123250397Sobrien{ 123390075Sobrien struct ttypes_filter **slot, *n; 123450397Sobrien 123590075Sobrien slot = (struct ttypes_filter **) 1236169689Skan htab_find_slot_with_hash (ttypes_hash, type, TREE_HASH (type), INSERT); 123750397Sobrien 123890075Sobrien if ((n = *slot) == NULL) 123950397Sobrien { 124090075Sobrien /* Filter value is a 1 based table index. */ 124150397Sobrien 1242169689Skan n = XNEW (struct ttypes_filter); 124390075Sobrien n->t = type; 1244169689Skan n->filter = VEC_length (tree, cfun->eh->ttype_data) + 1; 124590075Sobrien *slot = n; 124650397Sobrien 1247169689Skan VEC_safe_push (tree, gc, cfun->eh->ttype_data, type); 124850397Sobrien } 124950397Sobrien 125090075Sobrien return n->filter; 125150397Sobrien} 125250397Sobrien 125390075Sobrien/* Add LIST to cfun->eh->ehspec_data, using EHSPEC_HASH and TYPES_HASH 125490075Sobrien to speed up the search. Return the filter value to be used. */ 125550397Sobrien 125690075Sobrienstatic int 1257132718Skanadd_ehspec_entry (htab_t ehspec_hash, htab_t ttypes_hash, tree list) 125850397Sobrien{ 125990075Sobrien struct ttypes_filter **slot, *n; 126090075Sobrien struct ttypes_filter dummy; 126150397Sobrien 126290075Sobrien dummy.t = list; 126390075Sobrien slot = (struct ttypes_filter **) 126490075Sobrien htab_find_slot (ehspec_hash, &dummy, INSERT); 126550397Sobrien 126690075Sobrien if ((n = *slot) == NULL) 126790075Sobrien { 126890075Sobrien /* Filter value is a -1 based byte index into a uleb128 buffer. */ 126950397Sobrien 1270169689Skan n = XNEW (struct ttypes_filter); 127190075Sobrien n->t = list; 127290075Sobrien n->filter = -(VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) + 1); 127390075Sobrien *slot = n; 127450397Sobrien 1275169689Skan /* Generate a 0 terminated list of filter values. */ 127690075Sobrien for (; list ; list = TREE_CHAIN (list)) 1277169689Skan { 1278169689Skan if (targetm.arm_eabi_unwinder) 1279169689Skan VARRAY_PUSH_TREE (cfun->eh->ehspec_data, TREE_VALUE (list)); 1280169689Skan else 1281169689Skan { 1282169689Skan /* Look up each type in the list and encode its filter 1283169689Skan value as a uleb128. */ 1284169689Skan push_uleb128 (&cfun->eh->ehspec_data, 1285169689Skan add_ttypes_entry (ttypes_hash, TREE_VALUE (list))); 1286169689Skan } 1287169689Skan } 1288169689Skan if (targetm.arm_eabi_unwinder) 1289169689Skan VARRAY_PUSH_TREE (cfun->eh->ehspec_data, NULL_TREE); 1290169689Skan else 1291169689Skan VARRAY_PUSH_UCHAR (cfun->eh->ehspec_data, 0); 129290075Sobrien } 129390075Sobrien 129490075Sobrien return n->filter; 129590075Sobrien} 129690075Sobrien 129790075Sobrien/* Generate the action filter values to be used for CATCH and 129890075Sobrien ALLOWED_EXCEPTIONS regions. When using dwarf2 exception regions, 129990075Sobrien we use lots of landing pads, and so every type or list can share 130090075Sobrien the same filter value, which saves table space. */ 130190075Sobrien 130290075Sobrienstatic void 1303132718Skanassign_filter_values (void) 130450397Sobrien{ 130590075Sobrien int i; 130690075Sobrien htab_t ttypes, ehspec; 130750397Sobrien 1308169689Skan cfun->eh->ttype_data = VEC_alloc (tree, gc, 16); 1309169689Skan if (targetm.arm_eabi_unwinder) 1310169689Skan VARRAY_TREE_INIT (cfun->eh->ehspec_data, 64, "ehspec_data"); 1311169689Skan else 1312169689Skan VARRAY_UCHAR_INIT (cfun->eh->ehspec_data, 64, "ehspec_data"); 131350397Sobrien 131490075Sobrien ttypes = htab_create (31, ttypes_filter_hash, ttypes_filter_eq, free); 131590075Sobrien ehspec = htab_create (31, ehspec_filter_hash, ehspec_filter_eq, free); 131650397Sobrien 131790075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 131850397Sobrien { 1319169689Skan struct eh_region *r; 132050397Sobrien 1321169689Skan r = VEC_index (eh_region, cfun->eh->region_array, i); 1322169689Skan 132390075Sobrien /* Mind we don't process a region more than once. */ 132490075Sobrien if (!r || r->region_number != i) 132590075Sobrien continue; 132650397Sobrien 132790075Sobrien switch (r->type) 132890075Sobrien { 132990075Sobrien case ERT_CATCH: 133090075Sobrien /* Whatever type_list is (NULL or true list), we build a list 133190075Sobrien of filters for the region. */ 133290075Sobrien r->u.catch.filter_list = NULL_TREE; 133350397Sobrien 133490075Sobrien if (r->u.catch.type_list != NULL) 133590075Sobrien { 133690075Sobrien /* Get a filter value for each of the types caught and store 133790075Sobrien them in the region's dedicated list. */ 133890075Sobrien tree tp_node = r->u.catch.type_list; 133950397Sobrien 134090075Sobrien for (;tp_node; tp_node = TREE_CHAIN (tp_node)) 134190075Sobrien { 134290075Sobrien int flt = add_ttypes_entry (ttypes, TREE_VALUE (tp_node)); 1343169689Skan tree flt_node = build_int_cst (NULL_TREE, flt); 134450397Sobrien 134590075Sobrien r->u.catch.filter_list 134690075Sobrien = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list); 134790075Sobrien } 134890075Sobrien } 134990075Sobrien else 135090075Sobrien { 135190075Sobrien /* Get a filter value for the NULL list also since it will need 135290075Sobrien an action record anyway. */ 135390075Sobrien int flt = add_ttypes_entry (ttypes, NULL); 1354169689Skan tree flt_node = build_int_cst (NULL_TREE, flt); 135550397Sobrien 135690075Sobrien r->u.catch.filter_list 135790075Sobrien = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list); 135890075Sobrien } 135950397Sobrien 136090075Sobrien break; 136150397Sobrien 136290075Sobrien case ERT_ALLOWED_EXCEPTIONS: 136390075Sobrien r->u.allowed.filter 136490075Sobrien = add_ehspec_entry (ehspec, ttypes, r->u.allowed.type_list); 136590075Sobrien break; 136650397Sobrien 136790075Sobrien default: 136890075Sobrien break; 136990075Sobrien } 137050397Sobrien } 137190075Sobrien 137290075Sobrien htab_delete (ttypes); 137390075Sobrien htab_delete (ehspec); 137450397Sobrien} 137550397Sobrien 1376169689Skan/* Emit SEQ into basic block just before INSN (that is assumed to be 1377169689Skan first instruction of some existing BB and return the newly 1378169689Skan produced block. */ 1379169689Skanstatic basic_block 1380169689Skanemit_to_new_bb_before (rtx seq, rtx insn) 1381169689Skan{ 1382169689Skan rtx last; 1383169689Skan basic_block bb; 1384169689Skan edge e; 1385169689Skan edge_iterator ei; 1386169689Skan 1387169689Skan /* If there happens to be a fallthru edge (possibly created by cleanup_cfg 1388169689Skan call), we don't want it to go into newly created landing pad or other EH 1389169689Skan construct. */ 1390169689Skan for (ei = ei_start (BLOCK_FOR_INSN (insn)->preds); (e = ei_safe_edge (ei)); ) 1391169689Skan if (e->flags & EDGE_FALLTHRU) 1392169689Skan force_nonfallthru (e); 1393169689Skan else 1394169689Skan ei_next (&ei); 1395169689Skan last = emit_insn_before (seq, insn); 1396169689Skan if (BARRIER_P (last)) 1397169689Skan last = PREV_INSN (last); 1398169689Skan bb = create_basic_block (seq, last, BLOCK_FOR_INSN (insn)->prev_bb); 1399169689Skan update_bb_for_insn (bb); 1400169689Skan bb->flags |= BB_SUPERBLOCK; 1401169689Skan return bb; 1402169689Skan} 1403169689Skan 1404132718Skan/* Generate the code to actually handle exceptions, which will follow the 1405132718Skan landing pads. */ 1406132718Skan 140790075Sobrienstatic void 1408132718Skanbuild_post_landing_pads (void) 140950397Sobrien{ 141090075Sobrien int i; 141150397Sobrien 141290075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 141390075Sobrien { 1414169689Skan struct eh_region *region; 141590075Sobrien rtx seq; 141650397Sobrien 1417169689Skan region = VEC_index (eh_region, cfun->eh->region_array, i); 141890075Sobrien /* Mind we don't process a region more than once. */ 141990075Sobrien if (!region || region->region_number != i) 142090075Sobrien continue; 142150397Sobrien 142290075Sobrien switch (region->type) 142390075Sobrien { 142490075Sobrien case ERT_TRY: 142590075Sobrien /* ??? Collect the set of all non-overlapping catch handlers 142690075Sobrien all the way up the chain until blocked by a cleanup. */ 142790075Sobrien /* ??? Outer try regions can share landing pads with inner 142890075Sobrien try regions if the types are completely non-overlapping, 142990075Sobrien and there are no intervening cleanups. */ 143050397Sobrien 143190075Sobrien region->post_landing_pad = gen_label_rtx (); 143250397Sobrien 143390075Sobrien start_sequence (); 143450397Sobrien 143590075Sobrien emit_label (region->post_landing_pad); 143650397Sobrien 143790075Sobrien /* ??? It is mighty inconvenient to call back into the 143890075Sobrien switch statement generation code in expand_end_case. 143990075Sobrien Rapid prototyping sez a sequence of ifs. */ 144090075Sobrien { 144190075Sobrien struct eh_region *c; 144290075Sobrien for (c = region->u.try.catch; c ; c = c->u.catch.next_catch) 144390075Sobrien { 144490075Sobrien if (c->u.catch.type_list == NULL) 144590075Sobrien emit_jump (c->label); 144690075Sobrien else 144790075Sobrien { 144890075Sobrien /* Need for one cmp/jump per type caught. Each type 144990075Sobrien list entry has a matching entry in the filter list 145090075Sobrien (see assign_filter_values). */ 145190075Sobrien tree tp_node = c->u.catch.type_list; 145290075Sobrien tree flt_node = c->u.catch.filter_list; 145350397Sobrien 145490075Sobrien for (; tp_node; ) 145590075Sobrien { 145690075Sobrien emit_cmp_and_jump_insns 145790075Sobrien (cfun->eh->filter, 145890075Sobrien GEN_INT (tree_low_cst (TREE_VALUE (flt_node), 0)), 1459169689Skan EQ, NULL_RTX, 1460169689Skan targetm.eh_return_filter_mode (), 0, c->label); 146150397Sobrien 146290075Sobrien tp_node = TREE_CHAIN (tp_node); 146390075Sobrien flt_node = TREE_CHAIN (flt_node); 146490075Sobrien } 146590075Sobrien } 146690075Sobrien } 146790075Sobrien } 146850397Sobrien 146990075Sobrien /* We delay the generation of the _Unwind_Resume until we generate 147090075Sobrien landing pads. We emit a marker here so as to get good control 147190075Sobrien flow data in the meantime. */ 147290075Sobrien region->resume 147390075Sobrien = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number)); 147490075Sobrien emit_barrier (); 147550397Sobrien 147690075Sobrien seq = get_insns (); 147790075Sobrien end_sequence (); 147850397Sobrien 1479169689Skan emit_to_new_bb_before (seq, region->u.try.catch->label); 1480169689Skan 148190075Sobrien break; 148250397Sobrien 148390075Sobrien case ERT_ALLOWED_EXCEPTIONS: 148490075Sobrien region->post_landing_pad = gen_label_rtx (); 148550397Sobrien 148690075Sobrien start_sequence (); 148750397Sobrien 148890075Sobrien emit_label (region->post_landing_pad); 148950397Sobrien 149090075Sobrien emit_cmp_and_jump_insns (cfun->eh->filter, 149190075Sobrien GEN_INT (region->u.allowed.filter), 1492169689Skan EQ, NULL_RTX, 1493169689Skan targetm.eh_return_filter_mode (), 0, region->label); 149450397Sobrien 149590075Sobrien /* We delay the generation of the _Unwind_Resume until we generate 149690075Sobrien landing pads. We emit a marker here so as to get good control 149790075Sobrien flow data in the meantime. */ 149890075Sobrien region->resume 149990075Sobrien = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number)); 150090075Sobrien emit_barrier (); 150150397Sobrien 150290075Sobrien seq = get_insns (); 150390075Sobrien end_sequence (); 150490075Sobrien 1505169689Skan emit_to_new_bb_before (seq, region->label); 150690075Sobrien break; 150790075Sobrien 150890075Sobrien case ERT_CLEANUP: 150990075Sobrien case ERT_MUST_NOT_THROW: 151090075Sobrien region->post_landing_pad = region->label; 151190075Sobrien break; 151290075Sobrien 151390075Sobrien case ERT_CATCH: 151490075Sobrien case ERT_THROW: 151590075Sobrien /* Nothing to do. */ 151690075Sobrien break; 151790075Sobrien 151890075Sobrien default: 1519169689Skan gcc_unreachable (); 152090075Sobrien } 152190075Sobrien } 152250397Sobrien} 152350397Sobrien 152490075Sobrien/* Replace RESX patterns with jumps to the next handler if any, or calls to 152590075Sobrien _Unwind_Resume otherwise. */ 152650397Sobrien 152790075Sobrienstatic void 1528132718Skanconnect_post_landing_pads (void) 152950397Sobrien{ 153090075Sobrien int i; 153150397Sobrien 153290075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 153350397Sobrien { 1534169689Skan struct eh_region *region; 153590075Sobrien struct eh_region *outer; 153690075Sobrien rtx seq; 1537169689Skan rtx barrier; 153850397Sobrien 1539169689Skan region = VEC_index (eh_region, cfun->eh->region_array, i); 154090075Sobrien /* Mind we don't process a region more than once. */ 154190075Sobrien if (!region || region->region_number != i) 154290075Sobrien continue; 154350397Sobrien 154490075Sobrien /* If there is no RESX, or it has been deleted by flow, there's 154590075Sobrien nothing to fix up. */ 154690075Sobrien if (! region->resume || INSN_DELETED_P (region->resume)) 154790075Sobrien continue; 154850397Sobrien 154990075Sobrien /* Search for another landing pad in this function. */ 155090075Sobrien for (outer = region->outer; outer ; outer = outer->outer) 155190075Sobrien if (outer->post_landing_pad) 155290075Sobrien break; 155350397Sobrien 155490075Sobrien start_sequence (); 155550397Sobrien 155690075Sobrien if (outer) 1557169689Skan { 1558169689Skan edge e; 1559169689Skan basic_block src, dest; 1560169689Skan 1561169689Skan emit_jump (outer->post_landing_pad); 1562169689Skan src = BLOCK_FOR_INSN (region->resume); 1563169689Skan dest = BLOCK_FOR_INSN (outer->post_landing_pad); 1564169689Skan while (EDGE_COUNT (src->succs) > 0) 1565169689Skan remove_edge (EDGE_SUCC (src, 0)); 1566169689Skan e = make_edge (src, dest, 0); 1567169689Skan e->probability = REG_BR_PROB_BASE; 1568169689Skan e->count = src->count; 1569169689Skan } 157090075Sobrien else 1571169689Skan { 1572169689Skan emit_library_call (unwind_resume_libfunc, LCT_THROW, 1573169689Skan VOIDmode, 1, cfun->eh->exc_ptr, ptr_mode); 157450397Sobrien 1575169689Skan /* What we just emitted was a throwing libcall, so it got a 1576169689Skan barrier automatically added after it. If the last insn in 1577169689Skan the libcall sequence isn't the barrier, it's because the 1578169689Skan target emits multiple insns for a call, and there are insns 1579169689Skan after the actual call insn (which are redundant and would be 1580169689Skan optimized away). The barrier is inserted exactly after the 1581169689Skan call insn, so let's go get that and delete the insns after 1582169689Skan it, because below we need the barrier to be the last insn in 1583169689Skan the sequence. */ 1584169689Skan delete_insns_since (NEXT_INSN (last_call_insn ())); 1585169689Skan } 1586169689Skan 158790075Sobrien seq = get_insns (); 158890075Sobrien end_sequence (); 1589169689Skan barrier = emit_insn_before (seq, region->resume); 1590169689Skan /* Avoid duplicate barrier. */ 1591169689Skan gcc_assert (BARRIER_P (barrier)); 1592169689Skan delete_insn (barrier); 159390075Sobrien delete_insn (region->resume); 1594169689Skan 1595169689Skan /* ??? From tree-ssa we can wind up with catch regions whose 1596169689Skan label is not instantiated, but whose resx is present. Now 1597169689Skan that we've dealt with the resx, kill the region. */ 1598169689Skan if (region->label == NULL && region->type == ERT_CLEANUP) 1599169689Skan remove_eh_handler (region); 160050397Sobrien } 160150397Sobrien} 160250397Sobrien 160390075Sobrien 160490075Sobrienstatic void 1605132718Skandw2_build_landing_pads (void) 160650397Sobrien{ 160790075Sobrien int i; 160850397Sobrien 160990075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 161090075Sobrien { 1611169689Skan struct eh_region *region; 161290075Sobrien rtx seq; 1613169689Skan basic_block bb; 1614169689Skan edge e; 161550397Sobrien 1616169689Skan region = VEC_index (eh_region, cfun->eh->region_array, i); 161790075Sobrien /* Mind we don't process a region more than once. */ 161890075Sobrien if (!region || region->region_number != i) 161990075Sobrien continue; 162050397Sobrien 162190075Sobrien if (region->type != ERT_CLEANUP 162290075Sobrien && region->type != ERT_TRY 162390075Sobrien && region->type != ERT_ALLOWED_EXCEPTIONS) 162490075Sobrien continue; 162550397Sobrien 162690075Sobrien start_sequence (); 162750397Sobrien 162890075Sobrien region->landing_pad = gen_label_rtx (); 162990075Sobrien emit_label (region->landing_pad); 163050397Sobrien 163190075Sobrien#ifdef HAVE_exception_receiver 163290075Sobrien if (HAVE_exception_receiver) 163390075Sobrien emit_insn (gen_exception_receiver ()); 163490075Sobrien else 163590075Sobrien#endif 163690075Sobrien#ifdef HAVE_nonlocal_goto_receiver 163790075Sobrien if (HAVE_nonlocal_goto_receiver) 163890075Sobrien emit_insn (gen_nonlocal_goto_receiver ()); 163990075Sobrien else 164090075Sobrien#endif 164190075Sobrien { /* Nothing */ } 164250397Sobrien 164390075Sobrien emit_move_insn (cfun->eh->exc_ptr, 1644117395Skan gen_rtx_REG (ptr_mode, EH_RETURN_DATA_REGNO (0))); 164590075Sobrien emit_move_insn (cfun->eh->filter, 1646169689Skan gen_rtx_REG (targetm.eh_return_filter_mode (), 1647169689Skan EH_RETURN_DATA_REGNO (1))); 164852284Sobrien 164990075Sobrien seq = get_insns (); 165090075Sobrien end_sequence (); 165152284Sobrien 1652169689Skan bb = emit_to_new_bb_before (seq, region->post_landing_pad); 1653169689Skan e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU); 1654169689Skan e->count = bb->count; 1655169689Skan e->probability = REG_BR_PROB_BASE; 165652284Sobrien } 165750397Sobrien} 165850397Sobrien 165990075Sobrien 166090075Sobrienstruct sjlj_lp_info 166190075Sobrien{ 166290075Sobrien int directly_reachable; 166390075Sobrien int action_index; 166490075Sobrien int dispatch_index; 166590075Sobrien int call_site_index; 166690075Sobrien}; 166752284Sobrien 166890075Sobrienstatic bool 1669132718Skansjlj_find_directly_reachable_regions (struct sjlj_lp_info *lp_info) 167052284Sobrien{ 167190075Sobrien rtx insn; 167290075Sobrien bool found_one = false; 167352284Sobrien 167490075Sobrien for (insn = get_insns (); insn ; insn = NEXT_INSN (insn)) 167552284Sobrien { 167690075Sobrien struct eh_region *region; 167790075Sobrien enum reachable_code rc; 167890075Sobrien tree type_thrown; 167990075Sobrien rtx note; 168090075Sobrien 168190075Sobrien if (! INSN_P (insn)) 168290075Sobrien continue; 168390075Sobrien 168490075Sobrien note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 168590075Sobrien if (!note || INTVAL (XEXP (note, 0)) <= 0) 168690075Sobrien continue; 168790075Sobrien 1688169689Skan region = VEC_index (eh_region, cfun->eh->region_array, INTVAL (XEXP (note, 0))); 168990075Sobrien 169090075Sobrien type_thrown = NULL_TREE; 169190075Sobrien if (region->type == ERT_THROW) 169290075Sobrien { 169390075Sobrien type_thrown = region->u.throw.type; 169490075Sobrien region = region->outer; 169590075Sobrien } 169690075Sobrien 169790075Sobrien /* Find the first containing region that might handle the exception. 169890075Sobrien That's the landing pad to which we will transfer control. */ 169990075Sobrien rc = RNL_NOT_CAUGHT; 170090075Sobrien for (; region; region = region->outer) 170190075Sobrien { 1702169689Skan rc = reachable_next_level (region, type_thrown, NULL); 170390075Sobrien if (rc != RNL_NOT_CAUGHT) 170490075Sobrien break; 170590075Sobrien } 170690075Sobrien if (rc == RNL_MAYBE_CAUGHT || rc == RNL_CAUGHT) 170790075Sobrien { 170890075Sobrien lp_info[region->region_number].directly_reachable = 1; 170990075Sobrien found_one = true; 171090075Sobrien } 171152284Sobrien } 171252284Sobrien 171390075Sobrien return found_one; 171452284Sobrien} 171552284Sobrien 171690075Sobrienstatic void 1717132718Skansjlj_assign_call_site_values (rtx dispatch_label, struct sjlj_lp_info *lp_info) 171890075Sobrien{ 171990075Sobrien htab_t ar_hash; 172090075Sobrien int i, index; 172150397Sobrien 172290075Sobrien /* First task: build the action table. */ 172350397Sobrien 172490075Sobrien VARRAY_UCHAR_INIT (cfun->eh->action_record_data, 64, "action_record_data"); 172590075Sobrien ar_hash = htab_create (31, action_record_hash, action_record_eq, free); 172650397Sobrien 172790075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 172890075Sobrien if (lp_info[i].directly_reachable) 172990075Sobrien { 1730169689Skan struct eh_region *r = VEC_index (eh_region, cfun->eh->region_array, i); 1731169689Skan 173290075Sobrien r->landing_pad = dispatch_label; 173390075Sobrien lp_info[i].action_index = collect_one_action_chain (ar_hash, r); 173490075Sobrien if (lp_info[i].action_index != -1) 173590075Sobrien cfun->uses_eh_lsda = 1; 173690075Sobrien } 173750397Sobrien 173890075Sobrien htab_delete (ar_hash); 173950397Sobrien 174090075Sobrien /* Next: assign dispatch values. In dwarf2 terms, this would be the 174190075Sobrien landing pad label for the region. For sjlj though, there is one 174290075Sobrien common landing pad from which we dispatch to the post-landing pads. 174350397Sobrien 174490075Sobrien A region receives a dispatch index if it is directly reachable 174590075Sobrien and requires in-function processing. Regions that share post-landing 174690075Sobrien pads may share dispatch indices. */ 174790075Sobrien /* ??? Post-landing pad sharing doesn't actually happen at the moment 174890075Sobrien (see build_post_landing_pads) so we don't bother checking for it. */ 174950397Sobrien 175090075Sobrien index = 0; 175190075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 175290075Sobrien if (lp_info[i].directly_reachable) 175390075Sobrien lp_info[i].dispatch_index = index++; 175450397Sobrien 175590075Sobrien /* Finally: assign call-site values. If dwarf2 terms, this would be 175690075Sobrien the region number assigned by convert_to_eh_region_ranges, but 175790075Sobrien handles no-action and must-not-throw differently. */ 175850397Sobrien 175990075Sobrien call_site_base = 1; 176090075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 176190075Sobrien if (lp_info[i].directly_reachable) 176290075Sobrien { 176390075Sobrien int action = lp_info[i].action_index; 176490075Sobrien 176590075Sobrien /* Map must-not-throw to otherwise unused call-site index 0. */ 176690075Sobrien if (action == -2) 176790075Sobrien index = 0; 176890075Sobrien /* Map no-action to otherwise unused call-site index -1. */ 176990075Sobrien else if (action == -1) 177090075Sobrien index = -1; 177190075Sobrien /* Otherwise, look it up in the table. */ 177290075Sobrien else 177390075Sobrien index = add_call_site (GEN_INT (lp_info[i].dispatch_index), action); 177490075Sobrien 177590075Sobrien lp_info[i].call_site_index = index; 177690075Sobrien } 177790075Sobrien} 177890075Sobrien 177990075Sobrienstatic void 1780132718Skansjlj_mark_call_sites (struct sjlj_lp_info *lp_info) 178190075Sobrien{ 178290075Sobrien int last_call_site = -2; 178390075Sobrien rtx insn, mem; 178490075Sobrien 178590075Sobrien for (insn = get_insns (); insn ; insn = NEXT_INSN (insn)) 178650397Sobrien { 178790075Sobrien struct eh_region *region; 178890075Sobrien int this_call_site; 178990075Sobrien rtx note, before, p; 179050397Sobrien 179190075Sobrien /* Reset value tracking at extended basic block boundaries. */ 1792169689Skan if (LABEL_P (insn)) 179390075Sobrien last_call_site = -2; 179450397Sobrien 179590075Sobrien if (! INSN_P (insn)) 179690075Sobrien continue; 179750397Sobrien 179890075Sobrien note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 179990075Sobrien if (!note) 180090075Sobrien { 180190075Sobrien /* Calls (and trapping insns) without notes are outside any 180290075Sobrien exception handling region in this function. Mark them as 180390075Sobrien no action. */ 1804169689Skan if (CALL_P (insn) 180590075Sobrien || (flag_non_call_exceptions 180690075Sobrien && may_trap_p (PATTERN (insn)))) 180790075Sobrien this_call_site = -1; 180890075Sobrien else 180990075Sobrien continue; 181090075Sobrien } 181190075Sobrien else 181290075Sobrien { 181390075Sobrien /* Calls that are known to not throw need not be marked. */ 181490075Sobrien if (INTVAL (XEXP (note, 0)) <= 0) 181590075Sobrien continue; 181650397Sobrien 1817169689Skan region = VEC_index (eh_region, cfun->eh->region_array, INTVAL (XEXP (note, 0))); 181890075Sobrien this_call_site = lp_info[region->region_number].call_site_index; 181990075Sobrien } 182050397Sobrien 182190075Sobrien if (this_call_site == last_call_site) 182290075Sobrien continue; 182350397Sobrien 182490075Sobrien /* Don't separate a call from it's argument loads. */ 182590075Sobrien before = insn; 1826169689Skan if (CALL_P (insn)) 1827117395Skan before = find_first_parameter_load (insn, NULL_RTX); 182850397Sobrien 182990075Sobrien start_sequence (); 183090075Sobrien mem = adjust_address (cfun->eh->sjlj_fc, TYPE_MODE (integer_type_node), 183190075Sobrien sjlj_fc_call_site_ofs); 183290075Sobrien emit_move_insn (mem, GEN_INT (this_call_site)); 183390075Sobrien p = get_insns (); 183490075Sobrien end_sequence (); 183550397Sobrien 1836117395Skan emit_insn_before (p, before); 183790075Sobrien last_call_site = this_call_site; 183850397Sobrien } 183950397Sobrien} 184050397Sobrien 184190075Sobrien/* Construct the SjLj_Function_Context. */ 184250397Sobrien 184390075Sobrienstatic void 1844132718Skansjlj_emit_function_enter (rtx dispatch_label) 184550397Sobrien{ 184690075Sobrien rtx fn_begin, fc, mem, seq; 1847169689Skan bool fn_begin_outside_block; 184850397Sobrien 184990075Sobrien fc = cfun->eh->sjlj_fc; 185050397Sobrien 185190075Sobrien start_sequence (); 185250397Sobrien 185390075Sobrien /* We're storing this libcall's address into memory instead of 185490075Sobrien calling it directly. Thus, we must call assemble_external_libcall 185590075Sobrien here, as we can not depend on emit_library_call to do it for us. */ 185690075Sobrien assemble_external_libcall (eh_personality_libfunc); 185790075Sobrien mem = adjust_address (fc, Pmode, sjlj_fc_personality_ofs); 185890075Sobrien emit_move_insn (mem, eh_personality_libfunc); 185990075Sobrien 186090075Sobrien mem = adjust_address (fc, Pmode, sjlj_fc_lsda_ofs); 186190075Sobrien if (cfun->uses_eh_lsda) 186250397Sobrien { 186390075Sobrien char buf[20]; 1864132718Skan rtx sym; 1865132718Skan 1866117395Skan ASM_GENERATE_INTERNAL_LABEL (buf, "LLSDA", current_function_funcdef_no); 1867132718Skan sym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)); 1868132718Skan SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_LOCAL; 1869132718Skan emit_move_insn (mem, sym); 187050397Sobrien } 187190075Sobrien else 187290075Sobrien emit_move_insn (mem, const0_rtx); 187350397Sobrien 187490075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP 187590075Sobrien { 187690075Sobrien rtx x, note; 187790075Sobrien x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_RETURNS_TWICE, 187890075Sobrien TYPE_MODE (integer_type_node), 1, 187990075Sobrien plus_constant (XEXP (fc, 0), 188090075Sobrien sjlj_fc_jbuf_ofs), Pmode); 188150397Sobrien 1882132718Skan note = emit_note (NOTE_INSN_EXPECTED_VALUE); 188390075Sobrien NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, x, const0_rtx); 188450397Sobrien 188590075Sobrien emit_cmp_and_jump_insns (x, const0_rtx, NE, 0, 188690075Sobrien TYPE_MODE (integer_type_node), 0, dispatch_label); 188790075Sobrien } 188890075Sobrien#else 188990075Sobrien expand_builtin_setjmp_setup (plus_constant (XEXP (fc, 0), sjlj_fc_jbuf_ofs), 189090075Sobrien dispatch_label); 189190075Sobrien#endif 189250397Sobrien 189390075Sobrien emit_library_call (unwind_sjlj_register_libfunc, LCT_NORMAL, VOIDmode, 189490075Sobrien 1, XEXP (fc, 0), Pmode); 189590075Sobrien 189690075Sobrien seq = get_insns (); 189750397Sobrien end_sequence (); 189850397Sobrien 189990075Sobrien /* ??? Instead of doing this at the beginning of the function, 190090075Sobrien do this in a block that is at loop level 0 and dominates all 190190075Sobrien can_throw_internal instructions. */ 190250397Sobrien 1903169689Skan fn_begin_outside_block = true; 190490075Sobrien for (fn_begin = get_insns (); ; fn_begin = NEXT_INSN (fn_begin)) 1905169689Skan if (NOTE_P (fn_begin)) 1906169689Skan { 1907169689Skan if (NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG) 1908169689Skan break; 1909169689Skan else if (NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_BASIC_BLOCK) 1910169689Skan fn_begin_outside_block = false; 1911169689Skan } 1912169689Skan 1913169689Skan if (fn_begin_outside_block) 1914169689Skan insert_insn_on_edge (seq, single_succ_edge (ENTRY_BLOCK_PTR)); 1915169689Skan else 1916169689Skan emit_insn_after (seq, fn_begin); 191750397Sobrien} 191850397Sobrien 191990075Sobrien/* Call back from expand_function_end to know where we should put 192090075Sobrien the call to unwind_sjlj_unregister_libfunc if needed. */ 192150397Sobrien 192250397Sobrienvoid 1923132718Skansjlj_emit_function_exit_after (rtx after) 192450397Sobrien{ 192590075Sobrien cfun->eh->sjlj_exit_after = after; 192650397Sobrien} 192750397Sobrien 192890075Sobrienstatic void 1929132718Skansjlj_emit_function_exit (void) 193050397Sobrien{ 193190075Sobrien rtx seq; 1932169689Skan edge e; 1933169689Skan edge_iterator ei; 193450397Sobrien 193590075Sobrien start_sequence (); 193650397Sobrien 193790075Sobrien emit_library_call (unwind_sjlj_unregister_libfunc, LCT_NORMAL, VOIDmode, 193890075Sobrien 1, XEXP (cfun->eh->sjlj_fc, 0), Pmode); 193950397Sobrien 194090075Sobrien seq = get_insns (); 194190075Sobrien end_sequence (); 194250397Sobrien 194390075Sobrien /* ??? Really this can be done in any block at loop level 0 that 194490075Sobrien post-dominates all can_throw_internal instructions. This is 194590075Sobrien the last possible moment. */ 194650397Sobrien 1947169689Skan FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds) 1948169689Skan if (e->flags & EDGE_FALLTHRU) 1949169689Skan break; 1950169689Skan if (e) 1951169689Skan { 1952169689Skan rtx insn; 1953169689Skan 1954169689Skan /* Figure out whether the place we are supposed to insert libcall 1955169689Skan is inside the last basic block or after it. In the other case 1956169689Skan we need to emit to edge. */ 1957169689Skan gcc_assert (e->src->next_bb == EXIT_BLOCK_PTR); 1958169689Skan for (insn = BB_HEAD (e->src); ; insn = NEXT_INSN (insn)) 1959169689Skan { 1960169689Skan if (insn == cfun->eh->sjlj_exit_after) 1961169689Skan { 1962169689Skan if (LABEL_P (insn)) 1963169689Skan insn = NEXT_INSN (insn); 1964169689Skan emit_insn_after (seq, insn); 1965169689Skan return; 1966169689Skan } 1967169689Skan if (insn == BB_END (e->src)) 1968169689Skan break; 1969169689Skan } 1970169689Skan insert_insn_on_edge (seq, e); 1971169689Skan } 197290075Sobrien} 197350397Sobrien 197490075Sobrienstatic void 1975132718Skansjlj_emit_dispatch_table (rtx dispatch_label, struct sjlj_lp_info *lp_info) 197690075Sobrien{ 197790075Sobrien int i, first_reachable; 197890075Sobrien rtx mem, dispatch, seq, fc; 1979169689Skan rtx before; 1980169689Skan basic_block bb; 1981169689Skan edge e; 198250397Sobrien 198390075Sobrien fc = cfun->eh->sjlj_fc; 198450397Sobrien 198590075Sobrien start_sequence (); 198650397Sobrien 198790075Sobrien emit_label (dispatch_label); 198850397Sobrien 198990075Sobrien#ifndef DONT_USE_BUILTIN_SETJMP 199090075Sobrien expand_builtin_setjmp_receiver (dispatch_label); 199190075Sobrien#endif 199250397Sobrien 199390075Sobrien /* Load up dispatch index, exc_ptr and filter values from the 199490075Sobrien function context. */ 199590075Sobrien mem = adjust_address (fc, TYPE_MODE (integer_type_node), 199690075Sobrien sjlj_fc_call_site_ofs); 199790075Sobrien dispatch = copy_to_reg (mem); 199850397Sobrien 199990075Sobrien mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs); 2000132718Skan if (word_mode != ptr_mode) 200150397Sobrien { 200290075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED 2003132718Skan mem = convert_memory_address (ptr_mode, mem); 200490075Sobrien#else 2005132718Skan mem = convert_to_mode (ptr_mode, mem, 0); 200690075Sobrien#endif 200790075Sobrien } 200890075Sobrien emit_move_insn (cfun->eh->exc_ptr, mem); 200950397Sobrien 201090075Sobrien mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs + UNITS_PER_WORD); 201190075Sobrien emit_move_insn (cfun->eh->filter, mem); 201250397Sobrien 201390075Sobrien /* Jump to one of the directly reachable regions. */ 201490075Sobrien /* ??? This really ought to be using a switch statement. */ 201590075Sobrien 201690075Sobrien first_reachable = 0; 201790075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 201890075Sobrien { 201990075Sobrien if (! lp_info[i].directly_reachable) 202090075Sobrien continue; 202190075Sobrien 202290075Sobrien if (! first_reachable) 202350397Sobrien { 202490075Sobrien first_reachable = i; 202590075Sobrien continue; 202650397Sobrien } 202790075Sobrien 202890075Sobrien emit_cmp_and_jump_insns (dispatch, GEN_INT (lp_info[i].dispatch_index), 202990075Sobrien EQ, NULL_RTX, TYPE_MODE (integer_type_node), 0, 2030169689Skan ((struct eh_region *)VEC_index (eh_region, cfun->eh->region_array, i)) 2031169689Skan ->post_landing_pad); 203250397Sobrien } 203350397Sobrien 203490075Sobrien seq = get_insns (); 203590075Sobrien end_sequence (); 203650397Sobrien 2037169689Skan before = (((struct eh_region *)VEC_index (eh_region, cfun->eh->region_array, first_reachable)) 2038169689Skan ->post_landing_pad); 2039169689Skan 2040169689Skan bb = emit_to_new_bb_before (seq, before); 2041169689Skan e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU); 2042169689Skan e->count = bb->count; 2043169689Skan e->probability = REG_BR_PROB_BASE; 204450397Sobrien} 204550397Sobrien 204650397Sobrienstatic void 2047132718Skansjlj_build_landing_pads (void) 204850397Sobrien{ 204990075Sobrien struct sjlj_lp_info *lp_info; 205050397Sobrien 2051169689Skan lp_info = XCNEWVEC (struct sjlj_lp_info, cfun->eh->last_region_number + 1); 205250397Sobrien 205390075Sobrien if (sjlj_find_directly_reachable_regions (lp_info)) 205450397Sobrien { 205590075Sobrien rtx dispatch_label = gen_label_rtx (); 205652284Sobrien 205790075Sobrien cfun->eh->sjlj_fc 205890075Sobrien = assign_stack_local (TYPE_MODE (sjlj_fc_type_node), 205990075Sobrien int_size_in_bytes (sjlj_fc_type_node), 206090075Sobrien TYPE_ALIGN (sjlj_fc_type_node)); 206150397Sobrien 206290075Sobrien sjlj_assign_call_site_values (dispatch_label, lp_info); 206390075Sobrien sjlj_mark_call_sites (lp_info); 206450397Sobrien 206590075Sobrien sjlj_emit_function_enter (dispatch_label); 206690075Sobrien sjlj_emit_dispatch_table (dispatch_label, lp_info); 206790075Sobrien sjlj_emit_function_exit (); 206850397Sobrien } 206950397Sobrien 207090075Sobrien free (lp_info); 207150397Sobrien} 207250397Sobrien 207352284Sobrienvoid 2074132718Skanfinish_eh_generation (void) 207550397Sobrien{ 2076169689Skan basic_block bb; 2077169689Skan 207890075Sobrien /* Nothing to do if no regions created. */ 207990075Sobrien if (cfun->eh->region_tree == NULL) 208090075Sobrien return; 208150397Sobrien 208290075Sobrien /* The object here is to provide find_basic_blocks with detailed 208390075Sobrien information (via reachable_handlers) on how exception control 208490075Sobrien flows within the function. In this first pass, we can include 208590075Sobrien type information garnered from ERT_THROW and ERT_ALLOWED_EXCEPTIONS 208690075Sobrien regions, and hope that it will be useful in deleting unreachable 208790075Sobrien handlers. Subsequently, we will generate landing pads which will 208890075Sobrien connect many of the handlers, and then type information will not 208990075Sobrien be effective. Still, this is a win over previous implementations. */ 209050397Sobrien 209190075Sobrien /* These registers are used by the landing pads. Make sure they 209290075Sobrien have been generated. */ 209390075Sobrien get_exception_pointer (cfun); 209490075Sobrien get_exception_filter (cfun); 209550397Sobrien 209690075Sobrien /* Construct the landing pads. */ 209750397Sobrien 209890075Sobrien assign_filter_values (); 209990075Sobrien build_post_landing_pads (); 210090075Sobrien connect_post_landing_pads (); 210190075Sobrien if (USING_SJLJ_EXCEPTIONS) 210290075Sobrien sjlj_build_landing_pads (); 210390075Sobrien else 210490075Sobrien dw2_build_landing_pads (); 210550397Sobrien 210690075Sobrien cfun->eh->built_landing_pads = 1; 210750397Sobrien 210890075Sobrien /* We've totally changed the CFG. Start over. */ 210990075Sobrien find_exception_handler_labels (); 2110169689Skan break_superblocks (); 2111169689Skan if (USING_SJLJ_EXCEPTIONS) 2112169689Skan commit_edge_insertions (); 2113169689Skan FOR_EACH_BB (bb) 2114169689Skan { 2115169689Skan edge e; 2116169689Skan edge_iterator ei; 2117169689Skan bool eh = false; 2118169689Skan for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); ) 2119169689Skan { 2120169689Skan if (e->flags & EDGE_EH) 2121169689Skan { 2122169689Skan remove_edge (e); 2123169689Skan eh = true; 2124169689Skan } 2125169689Skan else 2126169689Skan ei_next (&ei); 2127169689Skan } 2128169689Skan if (eh) 2129169689Skan rtl_make_eh_edge (NULL, bb, BB_END (bb)); 2130169689Skan } 213190075Sobrien} 213290075Sobrien 213396263Sobrienstatic hashval_t 2134132718Skanehl_hash (const void *pentry) 213596263Sobrien{ 213696263Sobrien struct ehl_map_entry *entry = (struct ehl_map_entry *) pentry; 213796263Sobrien 213896263Sobrien /* 2^32 * ((sqrt(5) - 1) / 2) */ 213996263Sobrien const hashval_t scaled_golden_ratio = 0x9e3779b9; 214096263Sobrien return CODE_LABEL_NUMBER (entry->label) * scaled_golden_ratio; 214196263Sobrien} 214296263Sobrien 214396263Sobrienstatic int 2144132718Skanehl_eq (const void *pentry, const void *pdata) 214596263Sobrien{ 214696263Sobrien struct ehl_map_entry *entry = (struct ehl_map_entry *) pentry; 214796263Sobrien struct ehl_map_entry *data = (struct ehl_map_entry *) pdata; 214896263Sobrien 214996263Sobrien return entry->label == data->label; 215096263Sobrien} 215196263Sobrien 215290075Sobrien/* This section handles removing dead code for flow. */ 215352284Sobrien 215496263Sobrien/* Remove LABEL from exception_handler_label_map. */ 215550397Sobrien 215690075Sobrienstatic void 2157132718Skanremove_exception_handler_label (rtx label) 215890075Sobrien{ 215996263Sobrien struct ehl_map_entry **slot, tmp; 216050397Sobrien 216196263Sobrien /* If exception_handler_label_map was not built yet, 216290075Sobrien there is nothing to do. */ 2163117395Skan if (cfun->eh->exception_handler_label_map == NULL) 216490075Sobrien return; 216550397Sobrien 216696263Sobrien tmp.label = label; 216796263Sobrien slot = (struct ehl_map_entry **) 2168117395Skan htab_find_slot (cfun->eh->exception_handler_label_map, &tmp, NO_INSERT); 2169169689Skan gcc_assert (slot); 217050397Sobrien 2171117395Skan htab_clear_slot (cfun->eh->exception_handler_label_map, (void **) slot); 217250397Sobrien} 217350397Sobrien 217490075Sobrien/* Splice REGION from the region tree etc. */ 217550397Sobrien 217690075Sobrienstatic void 2177132718Skanremove_eh_handler (struct eh_region *region) 217850397Sobrien{ 217996263Sobrien struct eh_region **pp, **pp_start, *p, *outer, *inner; 218090075Sobrien rtx lab; 218150397Sobrien 218290075Sobrien /* For the benefit of efficiently handling REG_EH_REGION notes, 218390075Sobrien replace this region in the region array with its containing 218490075Sobrien region. Note that previous region deletions may result in 218596263Sobrien multiple copies of this region in the array, so we have a 218696263Sobrien list of alternate numbers by which we are known. */ 218750397Sobrien 218896263Sobrien outer = region->outer; 2189169689Skan VEC_replace (eh_region, cfun->eh->region_array, region->region_number, outer); 219096263Sobrien if (region->aka) 219196263Sobrien { 2192169689Skan unsigned i; 2193169689Skan bitmap_iterator bi; 2194169689Skan 2195169689Skan EXECUTE_IF_SET_IN_BITMAP (region->aka, 0, i, bi) 2196169689Skan { 2197169689Skan VEC_replace (eh_region, cfun->eh->region_array, i, outer); 2198169689Skan } 219996263Sobrien } 220096263Sobrien 220196263Sobrien if (outer) 220296263Sobrien { 220396263Sobrien if (!outer->aka) 2204117395Skan outer->aka = BITMAP_GGC_ALLOC (); 220596263Sobrien if (region->aka) 2206169689Skan bitmap_ior_into (outer->aka, region->aka); 220796263Sobrien bitmap_set_bit (outer->aka, region->region_number); 220896263Sobrien } 220996263Sobrien 221090075Sobrien if (cfun->eh->built_landing_pads) 221190075Sobrien lab = region->landing_pad; 221290075Sobrien else 221390075Sobrien lab = region->label; 221490075Sobrien if (lab) 221590075Sobrien remove_exception_handler_label (lab); 221650397Sobrien 221796263Sobrien if (outer) 221896263Sobrien pp_start = &outer->inner; 221990075Sobrien else 222096263Sobrien pp_start = &cfun->eh->region_tree; 222196263Sobrien for (pp = pp_start, p = *pp; p != region; pp = &p->next_peer, p = *pp) 222290075Sobrien continue; 222396263Sobrien *pp = region->next_peer; 222450397Sobrien 222596263Sobrien inner = region->inner; 222696263Sobrien if (inner) 222790075Sobrien { 222896263Sobrien for (p = inner; p->next_peer ; p = p->next_peer) 222996263Sobrien p->outer = outer; 223096263Sobrien p->outer = outer; 223196263Sobrien 223296263Sobrien p->next_peer = *pp_start; 223396263Sobrien *pp_start = inner; 223490075Sobrien } 223550397Sobrien 223690075Sobrien if (region->type == ERT_CATCH) 223790075Sobrien { 223890075Sobrien struct eh_region *try, *next, *prev; 223952284Sobrien 224090075Sobrien for (try = region->next_peer; 224190075Sobrien try->type == ERT_CATCH; 224290075Sobrien try = try->next_peer) 224390075Sobrien continue; 2244169689Skan gcc_assert (try->type == ERT_TRY); 224590075Sobrien 224690075Sobrien next = region->u.catch.next_catch; 224790075Sobrien prev = region->u.catch.prev_catch; 224890075Sobrien 224990075Sobrien if (next) 225090075Sobrien next->u.catch.prev_catch = prev; 225190075Sobrien else 225290075Sobrien try->u.try.last_catch = prev; 225390075Sobrien if (prev) 225490075Sobrien prev->u.catch.next_catch = next; 225590075Sobrien else 225690075Sobrien { 225790075Sobrien try->u.try.catch = next; 225890075Sobrien if (! next) 225990075Sobrien remove_eh_handler (try); 226090075Sobrien } 226190075Sobrien } 226250397Sobrien} 226350397Sobrien 226490075Sobrien/* LABEL heads a basic block that is about to be deleted. If this 226590075Sobrien label corresponds to an exception region, we may be able to 226690075Sobrien delete the region. */ 226750397Sobrien 226850397Sobrienvoid 2269132718Skanmaybe_remove_eh_handler (rtx label) 227050397Sobrien{ 227196263Sobrien struct ehl_map_entry **slot, tmp; 227296263Sobrien struct eh_region *region; 227350397Sobrien 227490075Sobrien /* ??? After generating landing pads, it's not so simple to determine 227590075Sobrien if the region data is completely unused. One must examine the 227690075Sobrien landing pad and the post landing pad, and whether an inner try block 227790075Sobrien is referencing the catch handlers directly. */ 227890075Sobrien if (cfun->eh->built_landing_pads) 227950397Sobrien return; 228050397Sobrien 228196263Sobrien tmp.label = label; 228296263Sobrien slot = (struct ehl_map_entry **) 2283117395Skan htab_find_slot (cfun->eh->exception_handler_label_map, &tmp, NO_INSERT); 228496263Sobrien if (! slot) 228596263Sobrien return; 228696263Sobrien region = (*slot)->region; 228796263Sobrien if (! region) 228896263Sobrien return; 228996263Sobrien 229096263Sobrien /* Flow will want to remove MUST_NOT_THROW regions as unreachable 229196263Sobrien because there is no path to the fallback call to terminate. 229296263Sobrien But the region continues to affect call-site data until there 229396263Sobrien are no more contained calls, which we don't see here. */ 229496263Sobrien if (region->type == ERT_MUST_NOT_THROW) 229550397Sobrien { 2296117395Skan htab_clear_slot (cfun->eh->exception_handler_label_map, (void **) slot); 229796263Sobrien region->label = NULL_RTX; 229850397Sobrien } 229996263Sobrien else 230096263Sobrien remove_eh_handler (region); 230150397Sobrien} 230250397Sobrien 230396263Sobrien/* Invokes CALLBACK for every exception handler label. Only used by old 230496263Sobrien loop hackery; should not be used by new code. */ 230596263Sobrien 230696263Sobrienvoid 2307132718Skanfor_each_eh_label (void (*callback) (rtx)) 230896263Sobrien{ 2309117395Skan htab_traverse (cfun->eh->exception_handler_label_map, for_each_eh_label_1, 2310132718Skan (void *) &callback); 231196263Sobrien} 231296263Sobrien 231396263Sobrienstatic int 2314132718Skanfor_each_eh_label_1 (void **pentry, void *data) 231596263Sobrien{ 231696263Sobrien struct ehl_map_entry *entry = *(struct ehl_map_entry **)pentry; 2317132718Skan void (*callback) (rtx) = *(void (**) (rtx)) data; 231896263Sobrien 231996263Sobrien (*callback) (entry->label); 232096263Sobrien return 1; 232196263Sobrien} 2322169689Skan 2323169689Skan/* Invoke CALLBACK for every exception region in the current function. */ 2324169689Skan 2325169689Skanvoid 2326169689Skanfor_each_eh_region (void (*callback) (struct eh_region *)) 2327169689Skan{ 2328169689Skan int i, n = cfun->eh->last_region_number; 2329169689Skan for (i = 1; i <= n; ++i) 2330169689Skan { 2331169689Skan struct eh_region *region; 2332169689Skan 2333169689Skan region = VEC_index (eh_region, cfun->eh->region_array, i); 2334169689Skan if (region) 2335169689Skan (*callback) (region); 2336169689Skan } 2337169689Skan} 233890075Sobrien 233990075Sobrien/* This section describes CFG exception edges for flow. */ 234050397Sobrien 234190075Sobrien/* For communicating between calls to reachable_next_level. */ 2342169689Skanstruct reachable_info 234350397Sobrien{ 234490075Sobrien tree types_caught; 234590075Sobrien tree types_allowed; 2346169689Skan void (*callback) (struct eh_region *, void *); 2347169689Skan void *callback_data; 2348169689Skan bool saw_any_handlers; 234990075Sobrien}; 235090075Sobrien 235190075Sobrien/* A subroutine of reachable_next_level. Return true if TYPE, or a 235290075Sobrien base class of TYPE, is in HANDLED. */ 235390075Sobrien 235490075Sobrienstatic int 2355132718Skancheck_handled (tree handled, tree type) 235690075Sobrien{ 235790075Sobrien tree t; 235890075Sobrien 235990075Sobrien /* We can check for exact matches without front-end help. */ 236090075Sobrien if (! lang_eh_type_covers) 236190075Sobrien { 236290075Sobrien for (t = handled; t ; t = TREE_CHAIN (t)) 236390075Sobrien if (TREE_VALUE (t) == type) 236490075Sobrien return 1; 236590075Sobrien } 236690075Sobrien else 236790075Sobrien { 236890075Sobrien for (t = handled; t ; t = TREE_CHAIN (t)) 236990075Sobrien if ((*lang_eh_type_covers) (TREE_VALUE (t), type)) 237090075Sobrien return 1; 237190075Sobrien } 237290075Sobrien 237350397Sobrien return 0; 237450397Sobrien} 237550397Sobrien 237690075Sobrien/* A subroutine of reachable_next_level. If we are collecting a list 237790075Sobrien of handlers, add one. After landing pad generation, reference 237890075Sobrien it instead of the handlers themselves. Further, the handlers are 237990075Sobrien all wired together, so by referencing one, we've got them all. 238090075Sobrien Before landing pad generation we reference each handler individually. 238150397Sobrien 238290075Sobrien LP_REGION contains the landing pad; REGION is the handler. */ 238350397Sobrien 238490075Sobrienstatic void 2385169689Skanadd_reachable_handler (struct reachable_info *info, 2386169689Skan struct eh_region *lp_region, struct eh_region *region) 238750397Sobrien{ 238890075Sobrien if (! info) 238950397Sobrien return; 239050397Sobrien 2391169689Skan info->saw_any_handlers = true; 2392169689Skan 239390075Sobrien if (cfun->eh->built_landing_pads) 2394169689Skan info->callback (lp_region, info->callback_data); 239590075Sobrien else 2396169689Skan info->callback (region, info->callback_data); 239750397Sobrien} 239850397Sobrien 239990075Sobrien/* Process one level of exception regions for reachability. 240090075Sobrien If TYPE_THROWN is non-null, then it is the *exact* type being 240190075Sobrien propagated. If INFO is non-null, then collect handler labels 240290075Sobrien and caught/allowed type information between invocations. */ 240350397Sobrien 240490075Sobrienstatic enum reachable_code 2405132718Skanreachable_next_level (struct eh_region *region, tree type_thrown, 2406132718Skan struct reachable_info *info) 240750397Sobrien{ 240890075Sobrien switch (region->type) 240990075Sobrien { 241090075Sobrien case ERT_CLEANUP: 241190075Sobrien /* Before landing-pad generation, we model control flow 241290075Sobrien directly to the individual handlers. In this way we can 241390075Sobrien see that catch handler types may shadow one another. */ 241490075Sobrien add_reachable_handler (info, region, region); 241590075Sobrien return RNL_MAYBE_CAUGHT; 241650397Sobrien 241790075Sobrien case ERT_TRY: 241890075Sobrien { 241990075Sobrien struct eh_region *c; 242090075Sobrien enum reachable_code ret = RNL_NOT_CAUGHT; 242150397Sobrien 242290075Sobrien for (c = region->u.try.catch; c ; c = c->u.catch.next_catch) 242390075Sobrien { 242490075Sobrien /* A catch-all handler ends the search. */ 242590075Sobrien if (c->u.catch.type_list == NULL) 242690075Sobrien { 242790075Sobrien add_reachable_handler (info, region, c); 242890075Sobrien return RNL_CAUGHT; 242990075Sobrien } 243050397Sobrien 243190075Sobrien if (type_thrown) 243290075Sobrien { 243390075Sobrien /* If we have at least one type match, end the search. */ 243490075Sobrien tree tp_node = c->u.catch.type_list; 243550397Sobrien 243690075Sobrien for (; tp_node; tp_node = TREE_CHAIN (tp_node)) 243790075Sobrien { 243890075Sobrien tree type = TREE_VALUE (tp_node); 243950397Sobrien 244090075Sobrien if (type == type_thrown 244190075Sobrien || (lang_eh_type_covers 244290075Sobrien && (*lang_eh_type_covers) (type, type_thrown))) 244390075Sobrien { 244490075Sobrien add_reachable_handler (info, region, c); 244590075Sobrien return RNL_CAUGHT; 244690075Sobrien } 244790075Sobrien } 244850397Sobrien 244990075Sobrien /* If we have definitive information of a match failure, 245090075Sobrien the catch won't trigger. */ 245190075Sobrien if (lang_eh_type_covers) 245290075Sobrien return RNL_NOT_CAUGHT; 245390075Sobrien } 245450397Sobrien 245590075Sobrien /* At this point, we either don't know what type is thrown or 245690075Sobrien don't have front-end assistance to help deciding if it is 245790075Sobrien covered by one of the types in the list for this region. 245850397Sobrien 245990075Sobrien We'd then like to add this region to the list of reachable 246090075Sobrien handlers since it is indeed potentially reachable based on the 246190075Sobrien information we have. 246250397Sobrien 246390075Sobrien Actually, this handler is for sure not reachable if all the 246490075Sobrien types it matches have already been caught. That is, it is only 246590075Sobrien potentially reachable if at least one of the types it catches 246690075Sobrien has not been previously caught. */ 246750397Sobrien 246890075Sobrien if (! info) 246990075Sobrien ret = RNL_MAYBE_CAUGHT; 247090075Sobrien else 247190075Sobrien { 247290075Sobrien tree tp_node = c->u.catch.type_list; 247390075Sobrien bool maybe_reachable = false; 247450397Sobrien 247590075Sobrien /* Compute the potential reachability of this handler and 247690075Sobrien update the list of types caught at the same time. */ 247790075Sobrien for (; tp_node; tp_node = TREE_CHAIN (tp_node)) 247890075Sobrien { 247990075Sobrien tree type = TREE_VALUE (tp_node); 248090075Sobrien 248190075Sobrien if (! check_handled (info->types_caught, type)) 248290075Sobrien { 248390075Sobrien info->types_caught 248490075Sobrien = tree_cons (NULL, type, info->types_caught); 248590075Sobrien 248690075Sobrien maybe_reachable = true; 248790075Sobrien } 248890075Sobrien } 248990075Sobrien 249090075Sobrien if (maybe_reachable) 249190075Sobrien { 249290075Sobrien add_reachable_handler (info, region, c); 249390075Sobrien 249490075Sobrien /* ??? If the catch type is a base class of every allowed 249590075Sobrien type, then we know we can stop the search. */ 249690075Sobrien ret = RNL_MAYBE_CAUGHT; 249790075Sobrien } 249890075Sobrien } 249990075Sobrien } 250090075Sobrien 250190075Sobrien return ret; 250290075Sobrien } 250390075Sobrien 250490075Sobrien case ERT_ALLOWED_EXCEPTIONS: 250590075Sobrien /* An empty list of types definitely ends the search. */ 250690075Sobrien if (region->u.allowed.type_list == NULL_TREE) 250790075Sobrien { 250890075Sobrien add_reachable_handler (info, region, region); 250990075Sobrien return RNL_CAUGHT; 251090075Sobrien } 251190075Sobrien 251290075Sobrien /* Collect a list of lists of allowed types for use in detecting 251390075Sobrien when a catch may be transformed into a catch-all. */ 251490075Sobrien if (info) 251590075Sobrien info->types_allowed = tree_cons (NULL_TREE, 251690075Sobrien region->u.allowed.type_list, 251790075Sobrien info->types_allowed); 251890075Sobrien 251990075Sobrien /* If we have definitive information about the type hierarchy, 252090075Sobrien then we can tell if the thrown type will pass through the 252190075Sobrien filter. */ 252290075Sobrien if (type_thrown && lang_eh_type_covers) 252390075Sobrien { 252490075Sobrien if (check_handled (region->u.allowed.type_list, type_thrown)) 252590075Sobrien return RNL_NOT_CAUGHT; 252690075Sobrien else 252790075Sobrien { 252890075Sobrien add_reachable_handler (info, region, region); 252990075Sobrien return RNL_CAUGHT; 253090075Sobrien } 253190075Sobrien } 253290075Sobrien 253390075Sobrien add_reachable_handler (info, region, region); 253490075Sobrien return RNL_MAYBE_CAUGHT; 253590075Sobrien 253690075Sobrien case ERT_CATCH: 2537132718Skan /* Catch regions are handled by their controlling try region. */ 253890075Sobrien return RNL_NOT_CAUGHT; 253990075Sobrien 254090075Sobrien case ERT_MUST_NOT_THROW: 254190075Sobrien /* Here we end our search, since no exceptions may propagate. 254290075Sobrien If we've touched down at some landing pad previous, then the 254390075Sobrien explicit function call we generated may be used. Otherwise 2544169689Skan the call is made by the runtime. 2545169689Skan 2546169689Skan Before inlining, do not perform this optimization. We may 2547169689Skan inline a subroutine that contains handlers, and that will 2548169689Skan change the value of saw_any_handlers. */ 2549169689Skan 2550169689Skan if ((info && info->saw_any_handlers) || !cfun->after_inlining) 255190075Sobrien { 255290075Sobrien add_reachable_handler (info, region, region); 2553117395Skan return RNL_CAUGHT; 255490075Sobrien } 255590075Sobrien else 255690075Sobrien return RNL_BLOCKED; 255790075Sobrien 255890075Sobrien case ERT_THROW: 255990075Sobrien case ERT_UNKNOWN: 256090075Sobrien /* Shouldn't see these here. */ 2561169689Skan gcc_unreachable (); 256290075Sobrien break; 2563169689Skan default: 2564169689Skan gcc_unreachable (); 256590075Sobrien } 256650397Sobrien} 256750397Sobrien 2568169689Skan/* Invoke CALLBACK on each region reachable from REGION_NUMBER. */ 256950397Sobrien 2570169689Skanvoid 2571169689Skanforeach_reachable_handler (int region_number, bool is_resx, 2572169689Skan void (*callback) (struct eh_region *, void *), 2573169689Skan void *callback_data) 257450397Sobrien{ 257590075Sobrien struct reachable_info info; 257690075Sobrien struct eh_region *region; 257790075Sobrien tree type_thrown; 257850397Sobrien 257990075Sobrien memset (&info, 0, sizeof (info)); 2580169689Skan info.callback = callback; 2581169689Skan info.callback_data = callback_data; 258250397Sobrien 2583169689Skan region = VEC_index (eh_region, cfun->eh->region_array, region_number); 258450397Sobrien 258590075Sobrien type_thrown = NULL_TREE; 2586169689Skan if (is_resx) 258790075Sobrien { 258890075Sobrien /* A RESX leaves a region instead of entering it. Thus the 258990075Sobrien region itself may have been deleted out from under us. */ 259090075Sobrien if (region == NULL) 2591169689Skan return; 259290075Sobrien region = region->outer; 259390075Sobrien } 259490075Sobrien else if (region->type == ERT_THROW) 259590075Sobrien { 259690075Sobrien type_thrown = region->u.throw.type; 259790075Sobrien region = region->outer; 259890075Sobrien } 259950397Sobrien 2600117395Skan while (region) 2601117395Skan { 2602117395Skan if (reachable_next_level (region, type_thrown, &info) >= RNL_CAUGHT) 2603117395Skan break; 2604117395Skan /* If we have processed one cleanup, there is no point in 2605117395Skan processing any more of them. Each cleanup will have an edge 2606117395Skan to the next outer cleanup region, so the flow graph will be 2607117395Skan accurate. */ 2608117395Skan if (region->type == ERT_CLEANUP) 2609117395Skan region = region->u.cleanup.prev_try; 2610117395Skan else 2611117395Skan region = region->outer; 2612117395Skan } 2613169689Skan} 2614132718Skan 2615169689Skan/* Retrieve a list of labels of exception handlers which can be 2616169689Skan reached by a given insn. */ 2617169689Skan 2618169689Skanstatic void 2619169689Skanarh_to_landing_pad (struct eh_region *region, void *data) 2620169689Skan{ 2621169689Skan rtx *p_handlers = data; 2622169689Skan if (! *p_handlers) 2623169689Skan *p_handlers = alloc_INSN_LIST (region->landing_pad, NULL_RTX); 262490075Sobrien} 262550397Sobrien 2626169689Skanstatic void 2627169689Skanarh_to_label (struct eh_region *region, void *data) 2628169689Skan{ 2629169689Skan rtx *p_handlers = data; 2630169689Skan *p_handlers = alloc_INSN_LIST (region->label, *p_handlers); 2631169689Skan} 2632169689Skan 2633169689Skanrtx 2634169689Skanreachable_handlers (rtx insn) 2635169689Skan{ 2636169689Skan bool is_resx = false; 2637169689Skan rtx handlers = NULL; 2638169689Skan int region_number; 2639169689Skan 2640169689Skan if (JUMP_P (insn) 2641169689Skan && GET_CODE (PATTERN (insn)) == RESX) 2642169689Skan { 2643169689Skan region_number = XINT (PATTERN (insn), 0); 2644169689Skan is_resx = true; 2645169689Skan } 2646169689Skan else 2647169689Skan { 2648169689Skan rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 2649169689Skan if (!note || INTVAL (XEXP (note, 0)) <= 0) 2650169689Skan return NULL; 2651169689Skan region_number = INTVAL (XEXP (note, 0)); 2652169689Skan } 2653169689Skan 2654169689Skan foreach_reachable_handler (region_number, is_resx, 2655169689Skan (cfun->eh->built_landing_pads 2656169689Skan ? arh_to_landing_pad 2657169689Skan : arh_to_label), 2658169689Skan &handlers); 2659169689Skan 2660169689Skan return handlers; 2661169689Skan} 2662169689Skan 266390075Sobrien/* Determine if the given INSN can throw an exception that is caught 266490075Sobrien within the function. */ 266590075Sobrien 266690075Sobrienbool 2667169689Skancan_throw_internal_1 (int region_number, bool is_resx) 266850397Sobrien{ 266990075Sobrien struct eh_region *region; 267090075Sobrien tree type_thrown; 267150397Sobrien 2672169689Skan region = VEC_index (eh_region, cfun->eh->region_array, region_number); 267350397Sobrien 267490075Sobrien type_thrown = NULL_TREE; 2675169689Skan if (is_resx) 2676169689Skan region = region->outer; 2677169689Skan else if (region->type == ERT_THROW) 267890075Sobrien { 267990075Sobrien type_thrown = region->u.throw.type; 268090075Sobrien region = region->outer; 268150397Sobrien } 268250397Sobrien 268390075Sobrien /* If this exception is ignored by each and every containing region, 268490075Sobrien then control passes straight out. The runtime may handle some 268590075Sobrien regions, which also do not require processing internally. */ 268690075Sobrien for (; region; region = region->outer) 268750397Sobrien { 268890075Sobrien enum reachable_code how = reachable_next_level (region, type_thrown, 0); 268990075Sobrien if (how == RNL_BLOCKED) 269090075Sobrien return false; 269190075Sobrien if (how != RNL_NOT_CAUGHT) 2692117395Skan return true; 269390075Sobrien } 269450397Sobrien 269590075Sobrien return false; 269690075Sobrien} 269750397Sobrien 2698169689Skanbool 2699169689Skancan_throw_internal (rtx insn) 2700169689Skan{ 2701169689Skan rtx note; 2702169689Skan 2703169689Skan if (! INSN_P (insn)) 2704169689Skan return false; 2705169689Skan 2706169689Skan if (JUMP_P (insn) 2707169689Skan && GET_CODE (PATTERN (insn)) == RESX 2708169689Skan && XINT (PATTERN (insn), 0) > 0) 2709169689Skan return can_throw_internal_1 (XINT (PATTERN (insn), 0), true); 2710169689Skan 2711169689Skan if (NONJUMP_INSN_P (insn) 2712169689Skan && GET_CODE (PATTERN (insn)) == SEQUENCE) 2713169689Skan insn = XVECEXP (PATTERN (insn), 0, 0); 2714169689Skan 2715169689Skan /* Every insn that might throw has an EH_REGION note. */ 2716169689Skan note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 2717169689Skan if (!note || INTVAL (XEXP (note, 0)) <= 0) 2718169689Skan return false; 2719169689Skan 2720169689Skan return can_throw_internal_1 (INTVAL (XEXP (note, 0)), false); 2721169689Skan} 2722169689Skan 272390075Sobrien/* Determine if the given INSN can throw an exception that is 272490075Sobrien visible outside the function. */ 272550397Sobrien 272690075Sobrienbool 2727169689Skancan_throw_external_1 (int region_number, bool is_resx) 272890075Sobrien{ 272990075Sobrien struct eh_region *region; 273090075Sobrien tree type_thrown; 2731169689Skan 2732169689Skan region = VEC_index (eh_region, cfun->eh->region_array, region_number); 2733169689Skan 2734169689Skan type_thrown = NULL_TREE; 2735169689Skan if (is_resx) 2736169689Skan region = region->outer; 2737169689Skan else if (region->type == ERT_THROW) 2738169689Skan { 2739169689Skan type_thrown = region->u.throw.type; 2740169689Skan region = region->outer; 2741169689Skan } 2742169689Skan 2743169689Skan /* If the exception is caught or blocked by any containing region, 2744169689Skan then it is not seen by any calling function. */ 2745169689Skan for (; region ; region = region->outer) 2746169689Skan if (reachable_next_level (region, type_thrown, NULL) >= RNL_CAUGHT) 2747169689Skan return false; 2748169689Skan 2749169689Skan return true; 2750169689Skan} 2751169689Skan 2752169689Skanbool 2753169689Skancan_throw_external (rtx insn) 2754169689Skan{ 275590075Sobrien rtx note; 275650397Sobrien 275790075Sobrien if (! INSN_P (insn)) 275890075Sobrien return false; 275990075Sobrien 2760169689Skan if (JUMP_P (insn) 2761169689Skan && GET_CODE (PATTERN (insn)) == RESX 2762169689Skan && XINT (PATTERN (insn), 0) > 0) 2763169689Skan return can_throw_external_1 (XINT (PATTERN (insn), 0), true); 2764169689Skan 2765169689Skan if (NONJUMP_INSN_P (insn) 276690075Sobrien && GET_CODE (PATTERN (insn)) == SEQUENCE) 276790075Sobrien insn = XVECEXP (PATTERN (insn), 0, 0); 276890075Sobrien 276990075Sobrien note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 277090075Sobrien if (!note) 277190075Sobrien { 277290075Sobrien /* Calls (and trapping insns) without notes are outside any 277390075Sobrien exception handling region in this function. We have to 277490075Sobrien assume it might throw. Given that the front end and middle 277590075Sobrien ends mark known NOTHROW functions, this isn't so wildly 277690075Sobrien inaccurate. */ 2777169689Skan return (CALL_P (insn) 277890075Sobrien || (flag_non_call_exceptions 277990075Sobrien && may_trap_p (PATTERN (insn)))); 278090075Sobrien } 278190075Sobrien if (INTVAL (XEXP (note, 0)) <= 0) 278290075Sobrien return false; 278390075Sobrien 2784169689Skan return can_throw_external_1 (INTVAL (XEXP (note, 0)), false); 278550397Sobrien} 278650397Sobrien 2787169689Skan/* Set TREE_NOTHROW and cfun->all_throwers_are_sibcalls. */ 278850397Sobrien 2789169689Skanunsigned int 2790132718Skanset_nothrow_function_flags (void) 279150397Sobrien{ 279250397Sobrien rtx insn; 2793132718Skan 2794169689Skan /* If we don't know that this implementation of the function will 2795169689Skan actually be used, then we must not set TREE_NOTHROW, since 2796169689Skan callers must not assume that this function does not throw. */ 2797169689Skan if (DECL_REPLACEABLE_P (current_function_decl)) 2798169689Skan return 0; 279950397Sobrien 2800169689Skan TREE_NOTHROW (current_function_decl) = 1; 2801169689Skan 2802117395Skan /* Assume cfun->all_throwers_are_sibcalls until we encounter 2803117395Skan something that can throw an exception. We specifically exempt 2804117395Skan CALL_INSNs that are SIBLING_CALL_P, as these are really jumps, 2805117395Skan and can't throw. Most CALL_INSNs are not SIBLING_CALL_P, so this 2806117395Skan is optimistic. */ 2807117395Skan 2808117395Skan cfun->all_throwers_are_sibcalls = 1; 2809117395Skan 281090075Sobrien if (! flag_exceptions) 2811169689Skan return 0; 2812132718Skan 281350397Sobrien for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 281490075Sobrien if (can_throw_external (insn)) 2815117395Skan { 2816169689Skan TREE_NOTHROW (current_function_decl) = 0; 2817117395Skan 2818169689Skan if (!CALL_P (insn) || !SIBLING_CALL_P (insn)) 2819117395Skan { 2820117395Skan cfun->all_throwers_are_sibcalls = 0; 2821169689Skan return 0; 2822117395Skan } 2823117395Skan } 2824117395Skan 282590075Sobrien for (insn = current_function_epilogue_delay_list; insn; 282690075Sobrien insn = XEXP (insn, 1)) 282790075Sobrien if (can_throw_external (insn)) 2828117395Skan { 2829169689Skan TREE_NOTHROW (current_function_decl) = 0; 283090075Sobrien 2831169689Skan if (!CALL_P (insn) || !SIBLING_CALL_P (insn)) 2832117395Skan { 2833117395Skan cfun->all_throwers_are_sibcalls = 0; 2834169689Skan return 0; 2835117395Skan } 2836117395Skan } 2837169689Skan return 0; 283850397Sobrien} 283990075Sobrien 2840169689Skanstruct tree_opt_pass pass_set_nothrow_function_flags = 2841169689Skan{ 2842169689Skan NULL, /* name */ 2843169689Skan NULL, /* gate */ 2844169689Skan set_nothrow_function_flags, /* execute */ 2845169689Skan NULL, /* sub */ 2846169689Skan NULL, /* next */ 2847169689Skan 0, /* static_pass_number */ 2848169689Skan 0, /* tv_id */ 2849169689Skan 0, /* properties_required */ 2850169689Skan 0, /* properties_provided */ 2851169689Skan 0, /* properties_destroyed */ 2852169689Skan 0, /* todo_flags_start */ 2853169689Skan 0, /* todo_flags_finish */ 2854169689Skan 0 /* letter */ 2855169689Skan}; 2856169689Skan 285750397Sobrien 285890075Sobrien/* Various hooks for unwind library. */ 285950397Sobrien 286050397Sobrien/* Do any necessary initialization to access arbitrary stack frames. 286150397Sobrien On the SPARC, this means flushing the register windows. */ 286250397Sobrien 286350397Sobrienvoid 2864132718Skanexpand_builtin_unwind_init (void) 286550397Sobrien{ 286650397Sobrien /* Set this so all the registers get saved in our frame; we need to be 286790075Sobrien able to copy the saved values for any registers from frames we unwind. */ 286850397Sobrien current_function_has_nonlocal_label = 1; 286950397Sobrien 287050397Sobrien#ifdef SETUP_FRAME_ADDRESSES 287150397Sobrien SETUP_FRAME_ADDRESSES (); 287250397Sobrien#endif 287350397Sobrien} 287450397Sobrien 287590075Sobrienrtx 2876132718Skanexpand_builtin_eh_return_data_regno (tree arglist) 287790075Sobrien{ 287890075Sobrien tree which = TREE_VALUE (arglist); 287990075Sobrien unsigned HOST_WIDE_INT iwhich; 288090075Sobrien 288190075Sobrien if (TREE_CODE (which) != INTEGER_CST) 288290075Sobrien { 2883169689Skan error ("argument of %<__builtin_eh_return_regno%> must be constant"); 288490075Sobrien return constm1_rtx; 288590075Sobrien } 288690075Sobrien 288790075Sobrien iwhich = tree_low_cst (which, 1); 288890075Sobrien iwhich = EH_RETURN_DATA_REGNO (iwhich); 288990075Sobrien if (iwhich == INVALID_REGNUM) 289090075Sobrien return constm1_rtx; 289190075Sobrien 289290075Sobrien#ifdef DWARF_FRAME_REGNUM 289390075Sobrien iwhich = DWARF_FRAME_REGNUM (iwhich); 289490075Sobrien#else 289590075Sobrien iwhich = DBX_REGISTER_NUMBER (iwhich); 289690075Sobrien#endif 289790075Sobrien 289890075Sobrien return GEN_INT (iwhich); 289990075Sobrien} 290090075Sobrien 290150397Sobrien/* Given a value extracted from the return address register or stack slot, 290250397Sobrien return the actual address encoded in that value. */ 290350397Sobrien 290450397Sobrienrtx 2905132718Skanexpand_builtin_extract_return_addr (tree addr_tree) 290650397Sobrien{ 290750397Sobrien rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0); 290890075Sobrien 2909117395Skan if (GET_MODE (addr) != Pmode 2910117395Skan && GET_MODE (addr) != VOIDmode) 2911117395Skan { 2912117395Skan#ifdef POINTERS_EXTEND_UNSIGNED 2913117395Skan addr = convert_memory_address (Pmode, addr); 2914117395Skan#else 2915117395Skan addr = convert_to_mode (Pmode, addr, 0); 2916117395Skan#endif 2917117395Skan } 2918117395Skan 291990075Sobrien /* First mask out any unwanted bits. */ 292090075Sobrien#ifdef MASK_RETURN_ADDR 292196263Sobrien expand_and (Pmode, addr, MASK_RETURN_ADDR, addr); 292290075Sobrien#endif 292390075Sobrien 292490075Sobrien /* Then adjust to find the real return address. */ 292590075Sobrien#if defined (RETURN_ADDR_OFFSET) 292690075Sobrien addr = plus_constant (addr, RETURN_ADDR_OFFSET); 292790075Sobrien#endif 292890075Sobrien 292990075Sobrien return addr; 293050397Sobrien} 293150397Sobrien 293250397Sobrien/* Given an actual address in addr_tree, do any necessary encoding 293350397Sobrien and return the value to be stored in the return address register or 293450397Sobrien stack slot so the epilogue will return to that address. */ 293550397Sobrien 293650397Sobrienrtx 2937132718Skanexpand_builtin_frob_return_addr (tree addr_tree) 293850397Sobrien{ 293990075Sobrien rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, 0); 294090075Sobrien 2941132718Skan addr = convert_memory_address (Pmode, addr); 294290075Sobrien 294350397Sobrien#ifdef RETURN_ADDR_OFFSET 294490075Sobrien addr = force_reg (Pmode, addr); 294550397Sobrien addr = plus_constant (addr, -RETURN_ADDR_OFFSET); 294650397Sobrien#endif 294790075Sobrien 294850397Sobrien return addr; 294950397Sobrien} 295050397Sobrien 295190075Sobrien/* Set up the epilogue with the magic bits we'll need to return to the 295290075Sobrien exception handler. */ 295350397Sobrien 295490075Sobrienvoid 2955132718Skanexpand_builtin_eh_return (tree stackadj_tree ATTRIBUTE_UNUSED, 2956132718Skan tree handler_tree) 295790075Sobrien{ 2958117395Skan rtx tmp; 295950397Sobrien 2960117395Skan#ifdef EH_RETURN_STACKADJ_RTX 2961117395Skan tmp = expand_expr (stackadj_tree, cfun->eh->ehr_stackadj, VOIDmode, 0); 2962132718Skan tmp = convert_memory_address (Pmode, tmp); 2963117395Skan if (!cfun->eh->ehr_stackadj) 2964117395Skan cfun->eh->ehr_stackadj = copy_to_reg (tmp); 2965117395Skan else if (tmp != cfun->eh->ehr_stackadj) 2966117395Skan emit_move_insn (cfun->eh->ehr_stackadj, tmp); 2967117395Skan#endif 296850397Sobrien 2969117395Skan tmp = expand_expr (handler_tree, cfun->eh->ehr_handler, VOIDmode, 0); 2970132718Skan tmp = convert_memory_address (Pmode, tmp); 2971117395Skan if (!cfun->eh->ehr_handler) 2972117395Skan cfun->eh->ehr_handler = copy_to_reg (tmp); 2973117395Skan else if (tmp != cfun->eh->ehr_handler) 2974117395Skan emit_move_insn (cfun->eh->ehr_handler, tmp); 297550397Sobrien 2976117395Skan if (!cfun->eh->ehr_label) 2977117395Skan cfun->eh->ehr_label = gen_label_rtx (); 297890075Sobrien emit_jump (cfun->eh->ehr_label); 297990075Sobrien} 298090075Sobrien 298190075Sobrienvoid 2982132718Skanexpand_eh_return (void) 298390075Sobrien{ 2984117395Skan rtx around_label; 298590075Sobrien 298690075Sobrien if (! cfun->eh->ehr_label) 298790075Sobrien return; 298890075Sobrien 298990075Sobrien current_function_calls_eh_return = 1; 299090075Sobrien 2991117395Skan#ifdef EH_RETURN_STACKADJ_RTX 2992117395Skan emit_move_insn (EH_RETURN_STACKADJ_RTX, const0_rtx); 2993117395Skan#endif 2994117395Skan 299590075Sobrien around_label = gen_label_rtx (); 299690075Sobrien emit_jump (around_label); 299790075Sobrien 299890075Sobrien emit_label (cfun->eh->ehr_label); 299990075Sobrien clobber_return_register (); 300090075Sobrien 3001117395Skan#ifdef EH_RETURN_STACKADJ_RTX 3002117395Skan emit_move_insn (EH_RETURN_STACKADJ_RTX, cfun->eh->ehr_stackadj); 3003117395Skan#endif 3004117395Skan 300590075Sobrien#ifdef HAVE_eh_return 300690075Sobrien if (HAVE_eh_return) 3007117395Skan emit_insn (gen_eh_return (cfun->eh->ehr_handler)); 300890075Sobrien else 300990075Sobrien#endif 301090075Sobrien { 3011117395Skan#ifdef EH_RETURN_HANDLER_RTX 3012117395Skan emit_move_insn (EH_RETURN_HANDLER_RTX, cfun->eh->ehr_handler); 3013117395Skan#else 3014117395Skan error ("__builtin_eh_return not supported on this target"); 3015117395Skan#endif 301650397Sobrien } 301750397Sobrien 301890075Sobrien emit_label (around_label); 301990075Sobrien} 3020132718Skan 3021132718Skan/* Convert a ptr_mode address ADDR_TREE to a Pmode address controlled by 3022132718Skan POINTERS_EXTEND_UNSIGNED and return it. */ 3023132718Skan 3024132718Skanrtx 3025132718Skanexpand_builtin_extend_pointer (tree addr_tree) 3026132718Skan{ 3027132718Skan rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, 0); 3028132718Skan int extend; 3029132718Skan 3030132718Skan#ifdef POINTERS_EXTEND_UNSIGNED 3031132718Skan extend = POINTERS_EXTEND_UNSIGNED; 3032132718Skan#else 3033132718Skan /* The previous EH code did an unsigned extend by default, so we do this also 3034132718Skan for consistency. */ 3035132718Skan extend = 1; 3036132718Skan#endif 3037132718Skan 3038132718Skan return convert_modes (word_mode, ptr_mode, addr, extend); 3039132718Skan} 304090075Sobrien 304190075Sobrien/* In the following functions, we represent entries in the action table 304290075Sobrien as 1-based indices. Special cases are: 304352284Sobrien 304490075Sobrien 0: null action record, non-null landing pad; implies cleanups 304590075Sobrien -1: null action record, null landing pad; implies no action 304690075Sobrien -2: no call-site entry; implies must_not_throw 304790075Sobrien -3: we have yet to process outer regions 304852284Sobrien 304990075Sobrien Further, no special cases apply to the "next" field of the record. 305090075Sobrien For next, 0 means end of list. */ 305190075Sobrien 305290075Sobrienstruct action_record 305390075Sobrien{ 305490075Sobrien int offset; 305590075Sobrien int filter; 305690075Sobrien int next; 305790075Sobrien}; 305890075Sobrien 305990075Sobrienstatic int 3060132718Skanaction_record_eq (const void *pentry, const void *pdata) 306190075Sobrien{ 306290075Sobrien const struct action_record *entry = (const struct action_record *) pentry; 306390075Sobrien const struct action_record *data = (const struct action_record *) pdata; 306490075Sobrien return entry->filter == data->filter && entry->next == data->next; 306550397Sobrien} 306650397Sobrien 306790075Sobrienstatic hashval_t 3068132718Skanaction_record_hash (const void *pentry) 306990075Sobrien{ 307090075Sobrien const struct action_record *entry = (const struct action_record *) pentry; 307190075Sobrien return entry->next * 1009 + entry->filter; 307290075Sobrien} 307350397Sobrien 307490075Sobrienstatic int 3075132718Skanadd_action_record (htab_t ar_hash, int filter, int next) 307650397Sobrien{ 307790075Sobrien struct action_record **slot, *new, tmp; 307890075Sobrien 307990075Sobrien tmp.filter = filter; 308090075Sobrien tmp.next = next; 308190075Sobrien slot = (struct action_record **) htab_find_slot (ar_hash, &tmp, INSERT); 308290075Sobrien 308390075Sobrien if ((new = *slot) == NULL) 308490075Sobrien { 3085132718Skan new = xmalloc (sizeof (*new)); 308690075Sobrien new->offset = VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) + 1; 308790075Sobrien new->filter = filter; 308890075Sobrien new->next = next; 308990075Sobrien *slot = new; 309090075Sobrien 309190075Sobrien /* The filter value goes in untouched. The link to the next 309290075Sobrien record is a "self-relative" byte offset, or zero to indicate 309390075Sobrien that there is no next record. So convert the absolute 1 based 309490075Sobrien indices we've been carrying around into a displacement. */ 309590075Sobrien 309690075Sobrien push_sleb128 (&cfun->eh->action_record_data, filter); 309790075Sobrien if (next) 309890075Sobrien next -= VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) + 1; 309990075Sobrien push_sleb128 (&cfun->eh->action_record_data, next); 310090075Sobrien } 310190075Sobrien 310290075Sobrien return new->offset; 310350397Sobrien} 310450397Sobrien 310590075Sobrienstatic int 3106132718Skancollect_one_action_chain (htab_t ar_hash, struct eh_region *region) 310790075Sobrien{ 310890075Sobrien struct eh_region *c; 310990075Sobrien int next; 311050397Sobrien 311190075Sobrien /* If we've reached the top of the region chain, then we have 311290075Sobrien no actions, and require no landing pad. */ 311390075Sobrien if (region == NULL) 311490075Sobrien return -1; 311590075Sobrien 311690075Sobrien switch (region->type) 311790075Sobrien { 311890075Sobrien case ERT_CLEANUP: 311990075Sobrien /* A cleanup adds a zero filter to the beginning of the chain, but 312090075Sobrien there are special cases to look out for. If there are *only* 312190075Sobrien cleanups along a path, then it compresses to a zero action. 312290075Sobrien Further, if there are multiple cleanups along a path, we only 312390075Sobrien need to represent one of them, as that is enough to trigger 312490075Sobrien entry to the landing pad at runtime. */ 312590075Sobrien next = collect_one_action_chain (ar_hash, region->outer); 312690075Sobrien if (next <= 0) 312790075Sobrien return 0; 312890075Sobrien for (c = region->outer; c ; c = c->outer) 312990075Sobrien if (c->type == ERT_CLEANUP) 313090075Sobrien return next; 313190075Sobrien return add_action_record (ar_hash, 0, next); 313290075Sobrien 313390075Sobrien case ERT_TRY: 313490075Sobrien /* Process the associated catch regions in reverse order. 313590075Sobrien If there's a catch-all handler, then we don't need to 313690075Sobrien search outer regions. Use a magic -3 value to record 313790075Sobrien that we haven't done the outer search. */ 313890075Sobrien next = -3; 313990075Sobrien for (c = region->u.try.last_catch; c ; c = c->u.catch.prev_catch) 314090075Sobrien { 314190075Sobrien if (c->u.catch.type_list == NULL) 314290075Sobrien { 314390075Sobrien /* Retrieve the filter from the head of the filter list 314490075Sobrien where we have stored it (see assign_filter_values). */ 314590075Sobrien int filter 314690075Sobrien = TREE_INT_CST_LOW (TREE_VALUE (c->u.catch.filter_list)); 314790075Sobrien 314890075Sobrien next = add_action_record (ar_hash, filter, 0); 314990075Sobrien } 315090075Sobrien else 315190075Sobrien { 315290075Sobrien /* Once the outer search is done, trigger an action record for 315390075Sobrien each filter we have. */ 315490075Sobrien tree flt_node; 315590075Sobrien 315690075Sobrien if (next == -3) 315790075Sobrien { 315890075Sobrien next = collect_one_action_chain (ar_hash, region->outer); 315990075Sobrien 316090075Sobrien /* If there is no next action, terminate the chain. */ 316190075Sobrien if (next == -1) 316290075Sobrien next = 0; 316390075Sobrien /* If all outer actions are cleanups or must_not_throw, 316490075Sobrien we'll have no action record for it, since we had wanted 316590075Sobrien to encode these states in the call-site record directly. 316690075Sobrien Add a cleanup action to the chain to catch these. */ 316790075Sobrien else if (next <= 0) 316890075Sobrien next = add_action_record (ar_hash, 0, 0); 316990075Sobrien } 317090075Sobrien 317190075Sobrien flt_node = c->u.catch.filter_list; 317290075Sobrien for (; flt_node; flt_node = TREE_CHAIN (flt_node)) 317390075Sobrien { 317490075Sobrien int filter = TREE_INT_CST_LOW (TREE_VALUE (flt_node)); 317590075Sobrien next = add_action_record (ar_hash, filter, next); 317690075Sobrien } 317790075Sobrien } 317890075Sobrien } 317990075Sobrien return next; 318090075Sobrien 318190075Sobrien case ERT_ALLOWED_EXCEPTIONS: 318290075Sobrien /* An exception specification adds its filter to the 318390075Sobrien beginning of the chain. */ 318490075Sobrien next = collect_one_action_chain (ar_hash, region->outer); 318590075Sobrien 3186132718Skan /* If there is no next action, terminate the chain. */ 3187132718Skan if (next == -1) 3188132718Skan next = 0; 3189132718Skan /* If all outer actions are cleanups or must_not_throw, 3190132718Skan we'll have no action record for it, since we had wanted 3191132718Skan to encode these states in the call-site record directly. 3192132718Skan Add a cleanup action to the chain to catch these. */ 3193132718Skan else if (next <= 0) 3194132718Skan next = add_action_record (ar_hash, 0, 0); 3195169689Skan 3196132718Skan return add_action_record (ar_hash, region->u.allowed.filter, next); 3197132718Skan 319890075Sobrien case ERT_MUST_NOT_THROW: 319990075Sobrien /* A must-not-throw region with no inner handlers or cleanups 320090075Sobrien requires no call-site entry. Note that this differs from 320190075Sobrien the no handler or cleanup case in that we do require an lsda 320290075Sobrien to be generated. Return a magic -2 value to record this. */ 320390075Sobrien return -2; 320490075Sobrien 320590075Sobrien case ERT_CATCH: 320690075Sobrien case ERT_THROW: 320790075Sobrien /* CATCH regions are handled in TRY above. THROW regions are 320890075Sobrien for optimization information only and produce no output. */ 320990075Sobrien return collect_one_action_chain (ar_hash, region->outer); 321090075Sobrien 321190075Sobrien default: 3212169689Skan gcc_unreachable (); 321390075Sobrien } 321490075Sobrien} 321590075Sobrien 321690075Sobrienstatic int 3217132718Skanadd_call_site (rtx landing_pad, int action) 321850397Sobrien{ 321990075Sobrien struct call_site_record *data = cfun->eh->call_site_data; 322090075Sobrien int used = cfun->eh->call_site_data_used; 322190075Sobrien int size = cfun->eh->call_site_data_size; 322250397Sobrien 322390075Sobrien if (used >= size) 322490075Sobrien { 322590075Sobrien size = (size ? size * 2 : 64); 3226132718Skan data = ggc_realloc (data, sizeof (*data) * size); 322790075Sobrien cfun->eh->call_site_data = data; 322890075Sobrien cfun->eh->call_site_data_size = size; 322990075Sobrien } 323090075Sobrien 323190075Sobrien data[used].landing_pad = landing_pad; 323290075Sobrien data[used].action = action; 323390075Sobrien 323490075Sobrien cfun->eh->call_site_data_used = used + 1; 323590075Sobrien 323690075Sobrien return used + call_site_base; 323750397Sobrien} 323850397Sobrien 323990075Sobrien/* Turn REG_EH_REGION notes back into NOTE_INSN_EH_REGION notes. 324090075Sobrien The new note numbers will not refer to region numbers, but 324190075Sobrien instead to call site entries. */ 324290075Sobrien 3243169689Skanunsigned int 3244132718Skanconvert_to_eh_region_ranges (void) 324550397Sobrien{ 324690075Sobrien rtx insn, iter, note; 324790075Sobrien htab_t ar_hash; 324890075Sobrien int last_action = -3; 324990075Sobrien rtx last_action_insn = NULL_RTX; 325090075Sobrien rtx last_landing_pad = NULL_RTX; 325190075Sobrien rtx first_no_action_insn = NULL_RTX; 325290075Sobrien int call_site = 0; 325350397Sobrien 325490075Sobrien if (USING_SJLJ_EXCEPTIONS || cfun->eh->region_tree == NULL) 3255169689Skan return 0; 325650397Sobrien 325790075Sobrien VARRAY_UCHAR_INIT (cfun->eh->action_record_data, 64, "action_record_data"); 325850397Sobrien 325990075Sobrien ar_hash = htab_create (31, action_record_hash, action_record_eq, free); 326050397Sobrien 326190075Sobrien for (iter = get_insns (); iter ; iter = NEXT_INSN (iter)) 326290075Sobrien if (INSN_P (iter)) 326390075Sobrien { 326490075Sobrien struct eh_region *region; 326590075Sobrien int this_action; 326690075Sobrien rtx this_landing_pad; 326750397Sobrien 326890075Sobrien insn = iter; 3269169689Skan if (NONJUMP_INSN_P (insn) 327090075Sobrien && GET_CODE (PATTERN (insn)) == SEQUENCE) 327190075Sobrien insn = XVECEXP (PATTERN (insn), 0, 0); 327250397Sobrien 327390075Sobrien note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 327490075Sobrien if (!note) 327590075Sobrien { 3276169689Skan if (! (CALL_P (insn) 327790075Sobrien || (flag_non_call_exceptions 327890075Sobrien && may_trap_p (PATTERN (insn))))) 327990075Sobrien continue; 328090075Sobrien this_action = -1; 328190075Sobrien region = NULL; 328290075Sobrien } 328390075Sobrien else 328490075Sobrien { 328590075Sobrien if (INTVAL (XEXP (note, 0)) <= 0) 328690075Sobrien continue; 3287169689Skan region = VEC_index (eh_region, cfun->eh->region_array, INTVAL (XEXP (note, 0))); 328890075Sobrien this_action = collect_one_action_chain (ar_hash, region); 328990075Sobrien } 329050397Sobrien 329190075Sobrien /* Existence of catch handlers, or must-not-throw regions 329290075Sobrien implies that an lsda is needed (even if empty). */ 329390075Sobrien if (this_action != -1) 329490075Sobrien cfun->uses_eh_lsda = 1; 329550397Sobrien 329690075Sobrien /* Delay creation of region notes for no-action regions 329790075Sobrien until we're sure that an lsda will be required. */ 329890075Sobrien else if (last_action == -3) 329990075Sobrien { 330090075Sobrien first_no_action_insn = iter; 330190075Sobrien last_action = -1; 330290075Sobrien } 330350397Sobrien 330490075Sobrien /* Cleanups and handlers may share action chains but not 330590075Sobrien landing pads. Collect the landing pad for this region. */ 330690075Sobrien if (this_action >= 0) 330790075Sobrien { 330890075Sobrien struct eh_region *o; 330990075Sobrien for (o = region; ! o->landing_pad ; o = o->outer) 331090075Sobrien continue; 331190075Sobrien this_landing_pad = o->landing_pad; 331290075Sobrien } 331390075Sobrien else 331490075Sobrien this_landing_pad = NULL_RTX; 331550397Sobrien 331690075Sobrien /* Differing actions or landing pads implies a change in call-site 331790075Sobrien info, which implies some EH_REGION note should be emitted. */ 331890075Sobrien if (last_action != this_action 331990075Sobrien || last_landing_pad != this_landing_pad) 332090075Sobrien { 332190075Sobrien /* If we'd not seen a previous action (-3) or the previous 332290075Sobrien action was must-not-throw (-2), then we do not need an 332390075Sobrien end note. */ 332490075Sobrien if (last_action >= -1) 332590075Sobrien { 332690075Sobrien /* If we delayed the creation of the begin, do it now. */ 332790075Sobrien if (first_no_action_insn) 332890075Sobrien { 332990075Sobrien call_site = add_call_site (NULL_RTX, 0); 333090075Sobrien note = emit_note_before (NOTE_INSN_EH_REGION_BEG, 333190075Sobrien first_no_action_insn); 333290075Sobrien NOTE_EH_HANDLER (note) = call_site; 333390075Sobrien first_no_action_insn = NULL_RTX; 333490075Sobrien } 333550397Sobrien 333690075Sobrien note = emit_note_after (NOTE_INSN_EH_REGION_END, 333790075Sobrien last_action_insn); 333890075Sobrien NOTE_EH_HANDLER (note) = call_site; 333990075Sobrien } 334052284Sobrien 334190075Sobrien /* If the new action is must-not-throw, then no region notes 334290075Sobrien are created. */ 334390075Sobrien if (this_action >= -1) 334490075Sobrien { 334590075Sobrien call_site = add_call_site (this_landing_pad, 334690075Sobrien this_action < 0 ? 0 : this_action); 334790075Sobrien note = emit_note_before (NOTE_INSN_EH_REGION_BEG, iter); 334890075Sobrien NOTE_EH_HANDLER (note) = call_site; 334990075Sobrien } 335052284Sobrien 335190075Sobrien last_action = this_action; 335290075Sobrien last_landing_pad = this_landing_pad; 335390075Sobrien } 335490075Sobrien last_action_insn = iter; 335590075Sobrien } 335652284Sobrien 335790075Sobrien if (last_action >= -1 && ! first_no_action_insn) 335890075Sobrien { 335990075Sobrien note = emit_note_after (NOTE_INSN_EH_REGION_END, last_action_insn); 336090075Sobrien NOTE_EH_HANDLER (note) = call_site; 336190075Sobrien } 336252284Sobrien 336390075Sobrien htab_delete (ar_hash); 3364169689Skan return 0; 336550397Sobrien} 336690075Sobrien 3367169689Skanstruct tree_opt_pass pass_convert_to_eh_region_ranges = 3368169689Skan{ 3369169689Skan "eh-ranges", /* name */ 3370169689Skan NULL, /* gate */ 3371169689Skan convert_to_eh_region_ranges, /* execute */ 3372169689Skan NULL, /* sub */ 3373169689Skan NULL, /* next */ 3374169689Skan 0, /* static_pass_number */ 3375169689Skan 0, /* tv_id */ 3376169689Skan 0, /* properties_required */ 3377169689Skan 0, /* properties_provided */ 3378169689Skan 0, /* properties_destroyed */ 3379169689Skan 0, /* todo_flags_start */ 3380169689Skan TODO_dump_func, /* todo_flags_finish */ 3381169689Skan 0 /* letter */ 3382169689Skan}; 3383169689Skan 338450397Sobrien 338590075Sobrienstatic void 3386132718Skanpush_uleb128 (varray_type *data_area, unsigned int value) 338790075Sobrien{ 338890075Sobrien do 338990075Sobrien { 339090075Sobrien unsigned char byte = value & 0x7f; 339190075Sobrien value >>= 7; 339290075Sobrien if (value) 339390075Sobrien byte |= 0x80; 339490075Sobrien VARRAY_PUSH_UCHAR (*data_area, byte); 339590075Sobrien } 339690075Sobrien while (value); 339790075Sobrien} 339850397Sobrien 339990075Sobrienstatic void 3400132718Skanpush_sleb128 (varray_type *data_area, int value) 340190075Sobrien{ 340290075Sobrien unsigned char byte; 340390075Sobrien int more; 340450397Sobrien 340590075Sobrien do 340690075Sobrien { 340790075Sobrien byte = value & 0x7f; 340890075Sobrien value >>= 7; 340990075Sobrien more = ! ((value == 0 && (byte & 0x40) == 0) 341090075Sobrien || (value == -1 && (byte & 0x40) != 0)); 341190075Sobrien if (more) 341290075Sobrien byte |= 0x80; 341390075Sobrien VARRAY_PUSH_UCHAR (*data_area, byte); 341490075Sobrien } 341590075Sobrien while (more); 341690075Sobrien} 341750397Sobrien 341890075Sobrien 341990075Sobrien#ifndef HAVE_AS_LEB128 342090075Sobrienstatic int 3421132718Skandw2_size_of_call_site_table (void) 342250397Sobrien{ 342390075Sobrien int n = cfun->eh->call_site_data_used; 342490075Sobrien int size = n * (4 + 4 + 4); 342590075Sobrien int i; 342650397Sobrien 342790075Sobrien for (i = 0; i < n; ++i) 342850397Sobrien { 342990075Sobrien struct call_site_record *cs = &cfun->eh->call_site_data[i]; 343090075Sobrien size += size_of_uleb128 (cs->action); 343150397Sobrien } 343290075Sobrien 343390075Sobrien return size; 343450397Sobrien} 343550397Sobrien 343690075Sobrienstatic int 3437132718Skansjlj_size_of_call_site_table (void) 343890075Sobrien{ 343990075Sobrien int n = cfun->eh->call_site_data_used; 344090075Sobrien int size = 0; 344190075Sobrien int i; 344250397Sobrien 344390075Sobrien for (i = 0; i < n; ++i) 344490075Sobrien { 344590075Sobrien struct call_site_record *cs = &cfun->eh->call_site_data[i]; 344690075Sobrien size += size_of_uleb128 (INTVAL (cs->landing_pad)); 344790075Sobrien size += size_of_uleb128 (cs->action); 344890075Sobrien } 344990075Sobrien 345090075Sobrien return size; 345190075Sobrien} 345290075Sobrien#endif 345390075Sobrien 345490075Sobrienstatic void 3455132718Skandw2_output_call_site_table (void) 345650397Sobrien{ 345790075Sobrien int n = cfun->eh->call_site_data_used; 345890075Sobrien int i; 345950397Sobrien 346090075Sobrien for (i = 0; i < n; ++i) 346150397Sobrien { 346290075Sobrien struct call_site_record *cs = &cfun->eh->call_site_data[i]; 346390075Sobrien char reg_start_lab[32]; 346490075Sobrien char reg_end_lab[32]; 346590075Sobrien char landing_pad_lab[32]; 346690075Sobrien 346790075Sobrien ASM_GENERATE_INTERNAL_LABEL (reg_start_lab, "LEHB", call_site_base + i); 346890075Sobrien ASM_GENERATE_INTERNAL_LABEL (reg_end_lab, "LEHE", call_site_base + i); 346990075Sobrien 347090075Sobrien if (cs->landing_pad) 347190075Sobrien ASM_GENERATE_INTERNAL_LABEL (landing_pad_lab, "L", 347290075Sobrien CODE_LABEL_NUMBER (cs->landing_pad)); 347390075Sobrien 347490075Sobrien /* ??? Perhaps use insn length scaling if the assembler supports 347590075Sobrien generic arithmetic. */ 347690075Sobrien /* ??? Perhaps use attr_length to choose data1 or data2 instead of 347790075Sobrien data4 if the function is small enough. */ 347890075Sobrien#ifdef HAVE_AS_LEB128 3479169689Skan dw2_asm_output_delta_uleb128 (reg_start_lab, 3480169689Skan current_function_func_begin_label, 348190075Sobrien "region %d start", i); 348290075Sobrien dw2_asm_output_delta_uleb128 (reg_end_lab, reg_start_lab, 348390075Sobrien "length"); 348490075Sobrien if (cs->landing_pad) 3485169689Skan dw2_asm_output_delta_uleb128 (landing_pad_lab, 3486169689Skan current_function_func_begin_label, 348790075Sobrien "landing pad"); 348890075Sobrien else 348990075Sobrien dw2_asm_output_data_uleb128 (0, "landing pad"); 349090075Sobrien#else 3491169689Skan dw2_asm_output_delta (4, reg_start_lab, 3492169689Skan current_function_func_begin_label, 349390075Sobrien "region %d start", i); 349490075Sobrien dw2_asm_output_delta (4, reg_end_lab, reg_start_lab, "length"); 349590075Sobrien if (cs->landing_pad) 3496169689Skan dw2_asm_output_delta (4, landing_pad_lab, 3497169689Skan current_function_func_begin_label, 349890075Sobrien "landing pad"); 349990075Sobrien else 350090075Sobrien dw2_asm_output_data (4, 0, "landing pad"); 350190075Sobrien#endif 350290075Sobrien dw2_asm_output_data_uleb128 (cs->action, "action"); 350350397Sobrien } 350490075Sobrien 350590075Sobrien call_site_base += n; 350650397Sobrien} 350750397Sobrien 350890075Sobrienstatic void 3509132718Skansjlj_output_call_site_table (void) 351090075Sobrien{ 351190075Sobrien int n = cfun->eh->call_site_data_used; 351290075Sobrien int i; 351350397Sobrien 351490075Sobrien for (i = 0; i < n; ++i) 351590075Sobrien { 351690075Sobrien struct call_site_record *cs = &cfun->eh->call_site_data[i]; 351790075Sobrien 351890075Sobrien dw2_asm_output_data_uleb128 (INTVAL (cs->landing_pad), 351990075Sobrien "region %d landing pad", i); 352090075Sobrien dw2_asm_output_data_uleb128 (cs->action, "action"); 352190075Sobrien } 352290075Sobrien 352390075Sobrien call_site_base += n; 352490075Sobrien} 352590075Sobrien 3526169689Skan#ifndef TARGET_UNWIND_INFO 3527169689Skan/* Switch to the section that should be used for exception tables. */ 3528117395Skan 3529169689Skanstatic void 3530169689Skanswitch_to_exception_section (void) 3531117395Skan{ 3532169689Skan if (exception_section == 0) 3533117395Skan { 3534169689Skan if (targetm.have_named_sections) 3535169689Skan { 3536169689Skan int flags; 3537117395Skan 3538169689Skan if (EH_TABLES_CAN_BE_READ_ONLY) 3539169689Skan { 3540169689Skan int tt_format = 3541169689Skan ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1); 3542169689Skan flags = ((! flag_pic 3543169689Skan || ((tt_format & 0x70) != DW_EH_PE_absptr 3544169689Skan && (tt_format & 0x70) != DW_EH_PE_aligned)) 3545169689Skan ? 0 : SECTION_WRITE); 3546169689Skan } 3547169689Skan else 3548169689Skan flags = SECTION_WRITE; 3549169689Skan exception_section = get_section (".gcc_except_table", flags, NULL); 3550169689Skan } 3551169689Skan else 3552169689Skan exception_section = flag_pic ? data_section : readonly_data_section; 3553169689Skan } 3554169689Skan switch_to_section (exception_section); 3555169689Skan} 3556117395Skan#endif 3557169689Skan 3558169689Skan 3559169689Skan/* Output a reference from an exception table to the type_info object TYPE. 3560169689Skan TT_FORMAT and TT_FORMAT_SIZE describe the DWARF encoding method used for 3561169689Skan the value. */ 3562169689Skan 3563169689Skanstatic void 3564169689Skanoutput_ttype (tree type, int tt_format, int tt_format_size) 3565169689Skan{ 3566169689Skan rtx value; 3567169689Skan bool public = true; 3568169689Skan 3569169689Skan if (type == NULL_TREE) 3570169689Skan value = const0_rtx; 3571169689Skan else 3572169689Skan { 3573169689Skan struct cgraph_varpool_node *node; 3574169689Skan 3575169689Skan type = lookup_type_for_runtime (type); 3576169689Skan value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER); 3577169689Skan 3578169689Skan /* Let cgraph know that the rtti decl is used. Not all of the 3579169689Skan paths below go through assemble_integer, which would take 3580169689Skan care of this for us. */ 3581169689Skan STRIP_NOPS (type); 3582169689Skan if (TREE_CODE (type) == ADDR_EXPR) 3583169689Skan { 3584169689Skan type = TREE_OPERAND (type, 0); 3585169689Skan if (TREE_CODE (type) == VAR_DECL) 3586169689Skan { 3587169689Skan node = cgraph_varpool_node (type); 3588169689Skan if (node) 3589169689Skan cgraph_varpool_mark_needed_node (node); 3590169689Skan public = TREE_PUBLIC (type); 3591169689Skan } 3592169689Skan } 3593169689Skan else 3594169689Skan gcc_assert (TREE_CODE (type) == INTEGER_CST); 3595117395Skan } 3596169689Skan 3597169689Skan /* Allow the target to override the type table entry format. */ 3598169689Skan if (targetm.asm_out.ttype (value)) 3599169689Skan return; 3600169689Skan 3601169689Skan if (tt_format == DW_EH_PE_absptr || tt_format == DW_EH_PE_aligned) 3602169689Skan assemble_integer (value, tt_format_size, 3603169689Skan tt_format_size * BITS_PER_UNIT, 1); 3604117395Skan else 3605169689Skan dw2_asm_output_encoded_addr_rtx (tt_format, value, public, NULL); 3606117395Skan} 3607117395Skan 3608117395Skanvoid 3609132718Skanoutput_function_exception_table (void) 361050397Sobrien{ 361190075Sobrien int tt_format, cs_format, lp_format, i, n; 361290075Sobrien#ifdef HAVE_AS_LEB128 361390075Sobrien char ttype_label[32]; 361490075Sobrien char cs_after_size_label[32]; 361590075Sobrien char cs_end_label[32]; 361690075Sobrien#else 361790075Sobrien int call_site_len; 361890075Sobrien#endif 361990075Sobrien int have_tt_data; 362090075Sobrien int tt_format_size = 0; 362150397Sobrien 3622169689Skan if (eh_personality_libfunc) 3623169689Skan assemble_external_libcall (eh_personality_libfunc); 3624169689Skan 362590075Sobrien /* Not all functions need anything. */ 362690075Sobrien if (! cfun->uses_eh_lsda) 362750397Sobrien return; 362850397Sobrien 3629169689Skan#ifdef TARGET_UNWIND_INFO 3630169689Skan /* TODO: Move this into target file. */ 363190075Sobrien fputs ("\t.personality\t", asm_out_file); 363290075Sobrien output_addr_const (asm_out_file, eh_personality_libfunc); 363390075Sobrien fputs ("\n\t.handlerdata\n", asm_out_file); 363490075Sobrien /* Note that varasm still thinks we're in the function's code section. 363590075Sobrien The ".endp" directive that will immediately follow will take us back. */ 363690075Sobrien#else 3637169689Skan switch_to_exception_section (); 363890075Sobrien#endif 363950397Sobrien 3640169689Skan /* If the target wants a label to begin the table, emit it here. */ 3641169689Skan targetm.asm_out.except_table_label (asm_out_file); 3642169689Skan 3643169689Skan have_tt_data = (VEC_length (tree, cfun->eh->ttype_data) > 0 364490075Sobrien || VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) > 0); 364550397Sobrien 364690075Sobrien /* Indicate the format of the @TType entries. */ 364790075Sobrien if (! have_tt_data) 364890075Sobrien tt_format = DW_EH_PE_omit; 364990075Sobrien else 365090075Sobrien { 365190075Sobrien tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1); 365290075Sobrien#ifdef HAVE_AS_LEB128 3653117395Skan ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT", 3654117395Skan current_function_funcdef_no); 365590075Sobrien#endif 365690075Sobrien tt_format_size = size_of_encoded_value (tt_format); 365750397Sobrien 365890075Sobrien assemble_align (tt_format_size * BITS_PER_UNIT); 365990075Sobrien } 366050397Sobrien 3661169689Skan targetm.asm_out.internal_label (asm_out_file, "LLSDA", 3662117395Skan current_function_funcdef_no); 366350397Sobrien 366490075Sobrien /* The LSDA header. */ 366550397Sobrien 366690075Sobrien /* Indicate the format of the landing pad start pointer. An omitted 366790075Sobrien field implies @LPStart == @Start. */ 366890075Sobrien /* Currently we always put @LPStart == @Start. This field would 366990075Sobrien be most useful in moving the landing pads completely out of 367090075Sobrien line to another section, but it could also be used to minimize 367190075Sobrien the size of uleb128 landing pad offsets. */ 367290075Sobrien lp_format = DW_EH_PE_omit; 367390075Sobrien dw2_asm_output_data (1, lp_format, "@LPStart format (%s)", 367490075Sobrien eh_data_format_name (lp_format)); 367550397Sobrien 367690075Sobrien /* @LPStart pointer would go here. */ 367750397Sobrien 367890075Sobrien dw2_asm_output_data (1, tt_format, "@TType format (%s)", 367990075Sobrien eh_data_format_name (tt_format)); 368050397Sobrien 368190075Sobrien#ifndef HAVE_AS_LEB128 368290075Sobrien if (USING_SJLJ_EXCEPTIONS) 368390075Sobrien call_site_len = sjlj_size_of_call_site_table (); 368490075Sobrien else 368590075Sobrien call_site_len = dw2_size_of_call_site_table (); 368690075Sobrien#endif 368790075Sobrien 368890075Sobrien /* A pc-relative 4-byte displacement to the @TType data. */ 368990075Sobrien if (have_tt_data) 369090075Sobrien { 369190075Sobrien#ifdef HAVE_AS_LEB128 369290075Sobrien char ttype_after_disp_label[32]; 369390075Sobrien ASM_GENERATE_INTERNAL_LABEL (ttype_after_disp_label, "LLSDATTD", 3694117395Skan current_function_funcdef_no); 369590075Sobrien dw2_asm_output_delta_uleb128 (ttype_label, ttype_after_disp_label, 369690075Sobrien "@TType base offset"); 369790075Sobrien ASM_OUTPUT_LABEL (asm_out_file, ttype_after_disp_label); 369890075Sobrien#else 369990075Sobrien /* Ug. Alignment queers things. */ 370090075Sobrien unsigned int before_disp, after_disp, last_disp, disp; 370190075Sobrien 370290075Sobrien before_disp = 1 + 1; 370390075Sobrien after_disp = (1 + size_of_uleb128 (call_site_len) 370490075Sobrien + call_site_len 370590075Sobrien + VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) 3706169689Skan + (VEC_length (tree, cfun->eh->ttype_data) 370790075Sobrien * tt_format_size)); 370890075Sobrien 370990075Sobrien disp = after_disp; 371090075Sobrien do 371190075Sobrien { 371290075Sobrien unsigned int disp_size, pad; 371390075Sobrien 371490075Sobrien last_disp = disp; 371590075Sobrien disp_size = size_of_uleb128 (disp); 371690075Sobrien pad = before_disp + disp_size + after_disp; 371790075Sobrien if (pad % tt_format_size) 371890075Sobrien pad = tt_format_size - (pad % tt_format_size); 371990075Sobrien else 372090075Sobrien pad = 0; 372190075Sobrien disp = after_disp + pad; 372290075Sobrien } 372390075Sobrien while (disp != last_disp); 372490075Sobrien 372590075Sobrien dw2_asm_output_data_uleb128 (disp, "@TType base offset"); 372690075Sobrien#endif 372790075Sobrien } 372890075Sobrien 372990075Sobrien /* Indicate the format of the call-site offsets. */ 373090075Sobrien#ifdef HAVE_AS_LEB128 373190075Sobrien cs_format = DW_EH_PE_uleb128; 373290075Sobrien#else 373390075Sobrien cs_format = DW_EH_PE_udata4; 373490075Sobrien#endif 373590075Sobrien dw2_asm_output_data (1, cs_format, "call-site format (%s)", 373690075Sobrien eh_data_format_name (cs_format)); 373790075Sobrien 373890075Sobrien#ifdef HAVE_AS_LEB128 373990075Sobrien ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label, "LLSDACSB", 3740117395Skan current_function_funcdef_no); 374190075Sobrien ASM_GENERATE_INTERNAL_LABEL (cs_end_label, "LLSDACSE", 3742117395Skan current_function_funcdef_no); 374390075Sobrien dw2_asm_output_delta_uleb128 (cs_end_label, cs_after_size_label, 374490075Sobrien "Call-site table length"); 374590075Sobrien ASM_OUTPUT_LABEL (asm_out_file, cs_after_size_label); 374690075Sobrien if (USING_SJLJ_EXCEPTIONS) 374790075Sobrien sjlj_output_call_site_table (); 374890075Sobrien else 374990075Sobrien dw2_output_call_site_table (); 375090075Sobrien ASM_OUTPUT_LABEL (asm_out_file, cs_end_label); 375190075Sobrien#else 375290075Sobrien dw2_asm_output_data_uleb128 (call_site_len,"Call-site table length"); 375390075Sobrien if (USING_SJLJ_EXCEPTIONS) 375490075Sobrien sjlj_output_call_site_table (); 375590075Sobrien else 375690075Sobrien dw2_output_call_site_table (); 375790075Sobrien#endif 375890075Sobrien 375990075Sobrien /* ??? Decode and interpret the data for flag_debug_asm. */ 376090075Sobrien n = VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data); 376190075Sobrien for (i = 0; i < n; ++i) 376290075Sobrien dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->action_record_data, i), 376390075Sobrien (i ? NULL : "Action record table")); 376490075Sobrien 376590075Sobrien if (have_tt_data) 376690075Sobrien assemble_align (tt_format_size * BITS_PER_UNIT); 376790075Sobrien 3768169689Skan i = VEC_length (tree, cfun->eh->ttype_data); 376990075Sobrien while (i-- > 0) 377090075Sobrien { 3771169689Skan tree type = VEC_index (tree, cfun->eh->ttype_data, i); 3772169689Skan output_ttype (type, tt_format, tt_format_size); 377390075Sobrien } 377490075Sobrien 377590075Sobrien#ifdef HAVE_AS_LEB128 377690075Sobrien if (have_tt_data) 377790075Sobrien ASM_OUTPUT_LABEL (asm_out_file, ttype_label); 377890075Sobrien#endif 377990075Sobrien 378090075Sobrien /* ??? Decode and interpret the data for flag_debug_asm. */ 378190075Sobrien n = VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data); 378290075Sobrien for (i = 0; i < n; ++i) 3783169689Skan { 3784169689Skan if (targetm.arm_eabi_unwinder) 3785169689Skan { 3786169689Skan tree type = VARRAY_TREE (cfun->eh->ehspec_data, i); 3787169689Skan output_ttype (type, tt_format, tt_format_size); 3788169689Skan } 3789169689Skan else 3790169689Skan dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->ehspec_data, i), 3791169689Skan (i ? NULL : "Exception specification table")); 3792169689Skan } 379390075Sobrien 3794169689Skan switch_to_section (current_function_section ()); 3795117395Skan} 379690075Sobrien 3797169689Skanvoid 3798169689Skanset_eh_throw_stmt_table (struct function *fun, struct htab *table) 3799169689Skan{ 3800169689Skan fun->eh->throw_stmt_table = table; 3801169689Skan} 3802169689Skan 3803169689Skanhtab_t 3804169689Skanget_eh_throw_stmt_table (struct function *fun) 3805169689Skan{ 3806169689Skan return fun->eh->throw_stmt_table; 3807169689Skan} 3808169689Skan 3809169689Skan/* Dump EH information to OUT. */ 3810169689Skanvoid 3811169689Skandump_eh_tree (FILE *out, struct function *fun) 3812169689Skan{ 3813169689Skan struct eh_region *i; 3814169689Skan int depth = 0; 3815169689Skan static const char * const type_name[] = {"unknown", "cleanup", "try", "catch", 3816169689Skan "allowed_exceptions", "must_not_throw", 3817169689Skan "throw"}; 3818169689Skan 3819169689Skan i = fun->eh->region_tree; 3820169689Skan if (! i) 3821169689Skan return; 3822169689Skan 3823169689Skan fprintf (out, "Eh tree:\n"); 3824169689Skan while (1) 3825169689Skan { 3826169689Skan fprintf (out, " %*s %i %s", depth * 2, "", 3827169689Skan i->region_number, type_name [(int)i->type]); 3828169689Skan if (i->tree_label) 3829169689Skan { 3830169689Skan fprintf (out, " tree_label:"); 3831169689Skan print_generic_expr (out, i->tree_label, 0); 3832169689Skan } 3833169689Skan fprintf (out, "\n"); 3834169689Skan /* If there are sub-regions, process them. */ 3835169689Skan if (i->inner) 3836169689Skan i = i->inner, depth++; 3837169689Skan /* If there are peers, process them. */ 3838169689Skan else if (i->next_peer) 3839169689Skan i = i->next_peer; 3840169689Skan /* Otherwise, step back up the tree to the next peer. */ 3841169689Skan else 3842169689Skan { 3843169689Skan do { 3844169689Skan i = i->outer; 3845169689Skan depth--; 3846169689Skan if (i == NULL) 3847169689Skan return; 3848169689Skan } while (i->next_peer == NULL); 3849169689Skan i = i->next_peer; 3850169689Skan } 3851169689Skan } 3852169689Skan} 3853169689Skan 3854169689Skan/* Verify some basic invariants on EH datastructures. Could be extended to 3855169689Skan catch more. */ 3856169689Skanvoid 3857169689Skanverify_eh_tree (struct function *fun) 3858169689Skan{ 3859169689Skan struct eh_region *i, *outer = NULL; 3860169689Skan bool err = false; 3861169689Skan int nvisited = 0; 3862169689Skan int count = 0; 3863169689Skan int j; 3864169689Skan int depth = 0; 3865169689Skan 3866169689Skan i = fun->eh->region_tree; 3867169689Skan if (! i) 3868169689Skan return; 3869169689Skan for (j = fun->eh->last_region_number; j > 0; --j) 3870169689Skan if ((i = VEC_index (eh_region, cfun->eh->region_array, j))) 3871169689Skan { 3872169689Skan count++; 3873169689Skan if (i->region_number != j) 3874169689Skan { 3875169689Skan error ("region_array is corrupted for region %i", i->region_number); 3876169689Skan err = true; 3877169689Skan } 3878169689Skan } 3879169689Skan 3880169689Skan while (1) 3881169689Skan { 3882169689Skan if (VEC_index (eh_region, cfun->eh->region_array, i->region_number) != i) 3883169689Skan { 3884169689Skan error ("region_array is corrupted for region %i", i->region_number); 3885169689Skan err = true; 3886169689Skan } 3887169689Skan if (i->outer != outer) 3888169689Skan { 3889169689Skan error ("outer block of region %i is wrong", i->region_number); 3890169689Skan err = true; 3891169689Skan } 3892169689Skan if (i->may_contain_throw && outer && !outer->may_contain_throw) 3893169689Skan { 3894169689Skan error ("region %i may contain throw and is contained in region that may not", 3895169689Skan i->region_number); 3896169689Skan err = true; 3897169689Skan } 3898169689Skan if (depth < 0) 3899169689Skan { 3900169689Skan error ("negative nesting depth of region %i", i->region_number); 3901169689Skan err = true; 3902169689Skan } 3903169689Skan nvisited ++; 3904169689Skan /* If there are sub-regions, process them. */ 3905169689Skan if (i->inner) 3906169689Skan outer = i, i = i->inner, depth++; 3907169689Skan /* If there are peers, process them. */ 3908169689Skan else if (i->next_peer) 3909169689Skan i = i->next_peer; 3910169689Skan /* Otherwise, step back up the tree to the next peer. */ 3911169689Skan else 3912169689Skan { 3913169689Skan do { 3914169689Skan i = i->outer; 3915169689Skan depth--; 3916169689Skan if (i == NULL) 3917169689Skan { 3918169689Skan if (depth != -1) 3919169689Skan { 3920169689Skan error ("tree list ends on depth %i", depth + 1); 3921169689Skan err = true; 3922169689Skan } 3923169689Skan if (count != nvisited) 3924169689Skan { 3925169689Skan error ("array does not match the region tree"); 3926169689Skan err = true; 3927169689Skan } 3928169689Skan if (err) 3929169689Skan { 3930169689Skan dump_eh_tree (stderr, fun); 3931169689Skan internal_error ("verify_eh_tree failed"); 3932169689Skan } 3933169689Skan return; 3934169689Skan } 3935169689Skan outer = i->outer; 3936169689Skan } while (i->next_peer == NULL); 3937169689Skan i = i->next_peer; 3938169689Skan } 3939169689Skan } 3940169689Skan} 3941169689Skan 3942169689Skan/* Initialize unwind_resume_libfunc. */ 3943169689Skan 3944169689Skanvoid 3945169689Skandefault_init_unwind_resume_libfunc (void) 3946169689Skan{ 3947169689Skan /* The default c++ routines aren't actually c++ specific, so use those. */ 3948169689Skan unwind_resume_libfunc = 3949169689Skan init_one_libfunc ( USING_SJLJ_EXCEPTIONS ? "_Unwind_SjLj_Resume" 3950169689Skan : "_Unwind_Resume"); 3951169689Skan} 3952169689Skan 3953169689Skan 3954169689Skanstatic bool 3955169689Skangate_handle_eh (void) 3956169689Skan{ 3957169689Skan return doing_eh (0); 3958169689Skan} 3959169689Skan 3960169689Skan/* Complete generation of exception handling code. */ 3961169689Skanstatic unsigned int 3962169689Skanrest_of_handle_eh (void) 3963169689Skan{ 3964169689Skan cleanup_cfg (CLEANUP_NO_INSN_DEL); 3965169689Skan finish_eh_generation (); 3966169689Skan cleanup_cfg (CLEANUP_NO_INSN_DEL); 3967169689Skan return 0; 3968169689Skan} 3969169689Skan 3970169689Skanstruct tree_opt_pass pass_rtl_eh = 3971169689Skan{ 3972169689Skan "eh", /* name */ 3973169689Skan gate_handle_eh, /* gate */ 3974169689Skan rest_of_handle_eh, /* execute */ 3975169689Skan NULL, /* sub */ 3976169689Skan NULL, /* next */ 3977169689Skan 0, /* static_pass_number */ 3978169689Skan TV_JUMP, /* tv_id */ 3979169689Skan 0, /* properties_required */ 3980169689Skan 0, /* properties_provided */ 3981169689Skan 0, /* properties_destroyed */ 3982169689Skan 0, /* todo_flags_start */ 3983169689Skan TODO_dump_func, /* todo_flags_finish */ 3984169689Skan 'h' /* letter */ 3985169689Skan}; 3986169689Skan 3987117395Skan#include "gt-except.h" 3988