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