except.c revision 90075
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" 7350397Sobrien 7490075Sobrien/* Provide defaults for stuff that may not be defined when using 7590075Sobrien sjlj exceptions. */ 7690075Sobrien#ifndef EH_RETURN_STACKADJ_RTX 7790075Sobrien#define EH_RETURN_STACKADJ_RTX 0 7890075Sobrien#endif 7990075Sobrien#ifndef EH_RETURN_HANDLER_RTX 8090075Sobrien#define EH_RETURN_HANDLER_RTX 0 8190075Sobrien#endif 8290075Sobrien#ifndef EH_RETURN_DATA_REGNO 8390075Sobrien#define EH_RETURN_DATA_REGNO(N) INVALID_REGNUM 8490075Sobrien#endif 8550397Sobrien 8650397Sobrien 8790075Sobrien/* Nonzero means enable synchronous exceptions for non-call instructions. */ 8890075Sobrienint flag_non_call_exceptions; 8950397Sobrien 9090075Sobrien/* Protect cleanup actions with must-not-throw regions, with a call 9190075Sobrien to the given failure handler. */ 9290075Sobrientree (*lang_protect_cleanup_actions) PARAMS ((void)); 9350397Sobrien 9490075Sobrien/* Return true if type A catches type B. */ 9590075Sobrienint (*lang_eh_type_covers) PARAMS ((tree a, tree b)); 9650397Sobrien 9790075Sobrien/* Map a type to a runtime object to match type. */ 9890075Sobrientree (*lang_eh_runtime_type) PARAMS ((tree)); 9950397Sobrien 10090075Sobrien/* A list of labels used for exception handlers. */ 10190075Sobrienrtx exception_handler_labels; 10250397Sobrien 10390075Sobrienstatic int call_site_base; 10490075Sobrienstatic unsigned int sjlj_funcdef_number; 10590075Sobrienstatic htab_t type_to_runtime_map; 10650397Sobrien 10790075Sobrien/* Describe the SjLj_Function_Context structure. */ 10890075Sobrienstatic 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. */ 11690075Sobrienstruct eh_region 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 12890075Sobrien /* Each region does exactly one thing. */ 12990075Sobrien enum eh_region_type 13090075Sobrien { 13190075Sobrien ERT_UNKNOWN = 0, 13290075Sobrien ERT_CLEANUP, 13390075Sobrien ERT_TRY, 13490075Sobrien ERT_CATCH, 13590075Sobrien ERT_ALLOWED_EXCEPTIONS, 13690075Sobrien ERT_MUST_NOT_THROW, 13790075Sobrien ERT_THROW, 13890075Sobrien ERT_FIXUP 13990075Sobrien } type; 14050397Sobrien 14190075Sobrien /* Holds the action to perform based on the preceding type. */ 14290075Sobrien union { 14390075Sobrien /* A list of catch blocks, a surrounding try block, 14490075Sobrien and the label for continuing after a catch. */ 14590075Sobrien struct { 14690075Sobrien struct eh_region *catch; 14790075Sobrien struct eh_region *last_catch; 14890075Sobrien struct eh_region *prev_try; 14990075Sobrien rtx continue_label; 15090075Sobrien } try; 15150397Sobrien 15290075Sobrien /* The list through the catch handlers, the list of type objects 15390075Sobrien matched, and the list of associated filters. */ 15490075Sobrien struct { 15590075Sobrien struct eh_region *next_catch; 15690075Sobrien struct eh_region *prev_catch; 15790075Sobrien tree type_list; 15890075Sobrien tree filter_list; 15990075Sobrien } catch; 16050397Sobrien 16190075Sobrien /* A tree_list of allowed types. */ 16290075Sobrien struct { 16390075Sobrien tree type_list; 16490075Sobrien int filter; 16590075Sobrien } allowed; 16650397Sobrien 16790075Sobrien /* The type given by a call to "throw foo();", or discovered 16890075Sobrien for a throw. */ 16990075Sobrien struct { 17090075Sobrien tree type; 17190075Sobrien } throw; 17250397Sobrien 17390075Sobrien /* Retain the cleanup expression even after expansion so that 17490075Sobrien we can match up fixup regions. */ 17590075Sobrien struct { 17690075Sobrien tree exp; 17790075Sobrien } cleanup; 17850397Sobrien 17990075Sobrien /* The real region (by expression and by pointer) that fixup code 18090075Sobrien should live in. */ 18190075Sobrien struct { 18290075Sobrien tree cleanup_exp; 18390075Sobrien struct eh_region *real_region; 18490075Sobrien } fixup; 18590075Sobrien } u; 18650397Sobrien 18790075Sobrien /* Entry point for this region's handler before landing pads are built. */ 18890075Sobrien rtx label; 18950397Sobrien 19090075Sobrien /* Entry point for this region's handler from the runtime eh library. */ 19190075Sobrien rtx landing_pad; 19250397Sobrien 19390075Sobrien /* Entry point for this region's handler from an inner region. */ 19490075Sobrien rtx post_landing_pad; 19550397Sobrien 19690075Sobrien /* The RESX insn for handing off control to the next outermost handler, 19790075Sobrien if appropriate. */ 19890075Sobrien rtx resume; 19990075Sobrien}; 20050397Sobrien 20190075Sobrien/* Used to save exception status for each function. */ 20290075Sobrienstruct eh_status 20390075Sobrien{ 20490075Sobrien /* The tree of all regions for this function. */ 20590075Sobrien struct eh_region *region_tree; 20650397Sobrien 20790075Sobrien /* The same information as an indexable array. */ 20890075Sobrien struct eh_region **region_array; 20950397Sobrien 21090075Sobrien /* The most recently open region. */ 21190075Sobrien struct eh_region *cur_region; 21250397Sobrien 21390075Sobrien /* This is the region for which we are processing catch blocks. */ 21490075Sobrien struct eh_region *try_region; 21550397Sobrien 21690075Sobrien /* A stack (TREE_LIST) of lists of handlers. The TREE_VALUE of each 21790075Sobrien node is itself a TREE_CHAINed list of handlers for regions that 21890075Sobrien are not yet closed. The TREE_VALUE of each entry contains the 21990075Sobrien handler for the corresponding entry on the ehstack. */ 22090075Sobrien tree protect_list; 22150397Sobrien 22290075Sobrien rtx filter; 22390075Sobrien rtx exc_ptr; 22450397Sobrien 22590075Sobrien int built_landing_pads; 22690075Sobrien int last_region_number; 22750397Sobrien 22890075Sobrien varray_type ttype_data; 22990075Sobrien varray_type ehspec_data; 23090075Sobrien varray_type action_record_data; 23150397Sobrien 23290075Sobrien struct call_site_record 23390075Sobrien { 23490075Sobrien rtx landing_pad; 23590075Sobrien int action; 23690075Sobrien } *call_site_data; 23790075Sobrien int call_site_data_used; 23890075Sobrien int call_site_data_size; 23950397Sobrien 24090075Sobrien rtx ehr_stackadj; 24190075Sobrien rtx ehr_handler; 24290075Sobrien rtx ehr_label; 24350397Sobrien 24490075Sobrien rtx sjlj_fc; 24590075Sobrien rtx sjlj_exit_after; 24690075Sobrien}; 24750397Sobrien 24890075Sobrien 24990075Sobrienstatic void mark_eh_region PARAMS ((struct eh_region *)); 25050397Sobrien 25190075Sobrienstatic int t2r_eq PARAMS ((const PTR, 25290075Sobrien const PTR)); 25390075Sobrienstatic hashval_t t2r_hash PARAMS ((const PTR)); 25490075Sobrienstatic int t2r_mark_1 PARAMS ((PTR *, PTR)); 25590075Sobrienstatic void t2r_mark PARAMS ((PTR)); 25690075Sobrienstatic void add_type_for_runtime PARAMS ((tree)); 25790075Sobrienstatic tree lookup_type_for_runtime PARAMS ((tree)); 25850397Sobrien 25990075Sobrienstatic struct eh_region *expand_eh_region_end PARAMS ((void)); 26050397Sobrien 26190075Sobrienstatic rtx get_exception_filter PARAMS ((struct function *)); 26250397Sobrien 26390075Sobrienstatic void collect_eh_region_array PARAMS ((void)); 26490075Sobrienstatic void resolve_fixup_regions PARAMS ((void)); 26590075Sobrienstatic void remove_fixup_regions PARAMS ((void)); 26690075Sobrienstatic void remove_unreachable_regions PARAMS ((rtx)); 26790075Sobrienstatic void convert_from_eh_region_ranges_1 PARAMS ((rtx *, int *, int)); 26850397Sobrien 26990075Sobrienstatic struct eh_region *duplicate_eh_region_1 PARAMS ((struct eh_region *, 27090075Sobrien struct inline_remap *)); 27190075Sobrienstatic void duplicate_eh_region_2 PARAMS ((struct eh_region *, 27290075Sobrien struct eh_region **)); 27390075Sobrienstatic int ttypes_filter_eq PARAMS ((const PTR, 27490075Sobrien const PTR)); 27590075Sobrienstatic hashval_t ttypes_filter_hash PARAMS ((const PTR)); 27690075Sobrienstatic int ehspec_filter_eq PARAMS ((const PTR, 27790075Sobrien const PTR)); 27890075Sobrienstatic hashval_t ehspec_filter_hash PARAMS ((const PTR)); 27990075Sobrienstatic int add_ttypes_entry PARAMS ((htab_t, tree)); 28090075Sobrienstatic int add_ehspec_entry PARAMS ((htab_t, htab_t, 28190075Sobrien tree)); 28290075Sobrienstatic void assign_filter_values PARAMS ((void)); 28390075Sobrienstatic void build_post_landing_pads PARAMS ((void)); 28490075Sobrienstatic void connect_post_landing_pads PARAMS ((void)); 28590075Sobrienstatic void dw2_build_landing_pads PARAMS ((void)); 28650397Sobrien 28790075Sobrienstruct sjlj_lp_info; 28890075Sobrienstatic bool sjlj_find_directly_reachable_regions 28990075Sobrien PARAMS ((struct sjlj_lp_info *)); 29090075Sobrienstatic void sjlj_assign_call_site_values 29190075Sobrien PARAMS ((rtx, struct sjlj_lp_info *)); 29290075Sobrienstatic void sjlj_mark_call_sites 29390075Sobrien PARAMS ((struct sjlj_lp_info *)); 29490075Sobrienstatic void sjlj_emit_function_enter PARAMS ((rtx)); 29590075Sobrienstatic void sjlj_emit_function_exit PARAMS ((void)); 29690075Sobrienstatic void sjlj_emit_dispatch_table 29790075Sobrien PARAMS ((rtx, struct sjlj_lp_info *)); 29890075Sobrienstatic void sjlj_build_landing_pads PARAMS ((void)); 29950397Sobrien 30090075Sobrienstatic void remove_exception_handler_label PARAMS ((rtx)); 30190075Sobrienstatic void remove_eh_handler PARAMS ((struct eh_region *)); 30250397Sobrien 30390075Sobrienstruct reachable_info; 30450397Sobrien 30590075Sobrien/* The return value of reachable_next_level. */ 30690075Sobrienenum reachable_code 30790075Sobrien{ 30890075Sobrien /* The given exception is not processed by the given region. */ 30990075Sobrien RNL_NOT_CAUGHT, 31090075Sobrien /* The given exception may need processing by the given region. */ 31190075Sobrien RNL_MAYBE_CAUGHT, 31290075Sobrien /* The given exception is completely processed by the given region. */ 31390075Sobrien RNL_CAUGHT, 31490075Sobrien /* The given exception is completely processed by the runtime. */ 31590075Sobrien RNL_BLOCKED 31690075Sobrien}; 31750397Sobrien 31890075Sobrienstatic int check_handled PARAMS ((tree, tree)); 31990075Sobrienstatic void add_reachable_handler 32090075Sobrien PARAMS ((struct reachable_info *, struct eh_region *, 32190075Sobrien struct eh_region *)); 32290075Sobrienstatic enum reachable_code reachable_next_level 32390075Sobrien PARAMS ((struct eh_region *, tree, struct reachable_info *)); 32450397Sobrien 32590075Sobrienstatic int action_record_eq PARAMS ((const PTR, 32690075Sobrien const PTR)); 32790075Sobrienstatic hashval_t action_record_hash PARAMS ((const PTR)); 32890075Sobrienstatic int add_action_record PARAMS ((htab_t, int, int)); 32990075Sobrienstatic int collect_one_action_chain PARAMS ((htab_t, 33090075Sobrien struct eh_region *)); 33190075Sobrienstatic int add_call_site PARAMS ((rtx, int)); 33250397Sobrien 33390075Sobrienstatic void push_uleb128 PARAMS ((varray_type *, 33490075Sobrien unsigned int)); 33590075Sobrienstatic void push_sleb128 PARAMS ((varray_type *, int)); 33690075Sobrien#ifndef HAVE_AS_LEB128 33790075Sobrienstatic int dw2_size_of_call_site_table PARAMS ((void)); 33890075Sobrienstatic int sjlj_size_of_call_site_table PARAMS ((void)); 33990075Sobrien#endif 34090075Sobrienstatic void dw2_output_call_site_table PARAMS ((void)); 34190075Sobrienstatic void sjlj_output_call_site_table PARAMS ((void)); 34250397Sobrien 34390075Sobrien 34490075Sobrien/* Routine to see if exception handling is turned on. 34590075Sobrien DO_WARN is non-zero if we want to inform the user that exception 34690075Sobrien handling is turned off. 34750397Sobrien 34890075Sobrien This is used to ensure that -fexceptions has been specified if the 34990075Sobrien compiler tries to use any exception-specific functions. */ 35050397Sobrien 35190075Sobrienint 35290075Sobriendoing_eh (do_warn) 35390075Sobrien int do_warn; 35490075Sobrien{ 35590075Sobrien if (! flag_exceptions) 35690075Sobrien { 35790075Sobrien static int warned = 0; 35890075Sobrien if (! warned && do_warn) 35990075Sobrien { 36090075Sobrien error ("exception handling disabled, use -fexceptions to enable"); 36190075Sobrien warned = 1; 36290075Sobrien } 36390075Sobrien return 0; 36490075Sobrien } 36590075Sobrien return 1; 36690075Sobrien} 36750397Sobrien 36890075Sobrien 36990075Sobrienvoid 37090075Sobrieninit_eh () 37190075Sobrien{ 37290075Sobrien ggc_add_rtx_root (&exception_handler_labels, 1); 37350397Sobrien 37490075Sobrien if (! flag_exceptions) 37590075Sobrien return; 37650397Sobrien 37790075Sobrien type_to_runtime_map = htab_create (31, t2r_hash, t2r_eq, NULL); 37890075Sobrien ggc_add_root (&type_to_runtime_map, 1, sizeof (htab_t), t2r_mark); 37950397Sobrien 38090075Sobrien /* Create the SjLj_Function_Context structure. This should match 38190075Sobrien the definition in unwind-sjlj.c. */ 38290075Sobrien if (USING_SJLJ_EXCEPTIONS) 38390075Sobrien { 38490075Sobrien tree f_jbuf, f_per, f_lsda, f_prev, f_cs, f_data, tmp; 38550397Sobrien 38690075Sobrien sjlj_fc_type_node = make_lang_type (RECORD_TYPE); 38790075Sobrien ggc_add_tree_root (&sjlj_fc_type_node, 1); 38850397Sobrien 38990075Sobrien f_prev = build_decl (FIELD_DECL, get_identifier ("__prev"), 39090075Sobrien build_pointer_type (sjlj_fc_type_node)); 39190075Sobrien DECL_FIELD_CONTEXT (f_prev) = sjlj_fc_type_node; 39250397Sobrien 39390075Sobrien f_cs = build_decl (FIELD_DECL, get_identifier ("__call_site"), 39490075Sobrien integer_type_node); 39590075Sobrien DECL_FIELD_CONTEXT (f_cs) = sjlj_fc_type_node; 39650397Sobrien 39790075Sobrien tmp = build_index_type (build_int_2 (4 - 1, 0)); 39890075Sobrien tmp = build_array_type (type_for_mode (word_mode, 1), tmp); 39990075Sobrien f_data = build_decl (FIELD_DECL, get_identifier ("__data"), tmp); 40090075Sobrien DECL_FIELD_CONTEXT (f_data) = sjlj_fc_type_node; 40150397Sobrien 40290075Sobrien f_per = build_decl (FIELD_DECL, get_identifier ("__personality"), 40390075Sobrien ptr_type_node); 40490075Sobrien DECL_FIELD_CONTEXT (f_per) = sjlj_fc_type_node; 40550397Sobrien 40690075Sobrien f_lsda = build_decl (FIELD_DECL, get_identifier ("__lsda"), 40790075Sobrien ptr_type_node); 40890075Sobrien DECL_FIELD_CONTEXT (f_lsda) = sjlj_fc_type_node; 40950397Sobrien 41090075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP 41190075Sobrien#ifdef JMP_BUF_SIZE 41290075Sobrien tmp = build_int_2 (JMP_BUF_SIZE - 1, 0); 41390075Sobrien#else 41490075Sobrien /* Should be large enough for most systems, if it is not, 41590075Sobrien JMP_BUF_SIZE should be defined with the proper value. It will 41690075Sobrien also tend to be larger than necessary for most systems, a more 41790075Sobrien optimal port will define JMP_BUF_SIZE. */ 41890075Sobrien tmp = build_int_2 (FIRST_PSEUDO_REGISTER + 2 - 1, 0); 41990075Sobrien#endif 42090075Sobrien#else 42190075Sobrien /* This is 2 for builtin_setjmp, plus whatever the target requires 42290075Sobrien via STACK_SAVEAREA_MODE (SAVE_NONLOCAL). */ 42390075Sobrien tmp = build_int_2 ((GET_MODE_SIZE (STACK_SAVEAREA_MODE (SAVE_NONLOCAL)) 42490075Sobrien / GET_MODE_SIZE (Pmode)) + 2 - 1, 0); 42590075Sobrien#endif 42690075Sobrien tmp = build_index_type (tmp); 42790075Sobrien tmp = build_array_type (ptr_type_node, tmp); 42890075Sobrien f_jbuf = build_decl (FIELD_DECL, get_identifier ("__jbuf"), tmp); 42990075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP 43090075Sobrien /* We don't know what the alignment requirements of the 43190075Sobrien runtime's jmp_buf has. Overestimate. */ 43290075Sobrien DECL_ALIGN (f_jbuf) = BIGGEST_ALIGNMENT; 43390075Sobrien DECL_USER_ALIGN (f_jbuf) = 1; 43490075Sobrien#endif 43590075Sobrien DECL_FIELD_CONTEXT (f_jbuf) = sjlj_fc_type_node; 43650397Sobrien 43790075Sobrien TYPE_FIELDS (sjlj_fc_type_node) = f_prev; 43890075Sobrien TREE_CHAIN (f_prev) = f_cs; 43990075Sobrien TREE_CHAIN (f_cs) = f_data; 44090075Sobrien TREE_CHAIN (f_data) = f_per; 44190075Sobrien TREE_CHAIN (f_per) = f_lsda; 44290075Sobrien TREE_CHAIN (f_lsda) = f_jbuf; 44350397Sobrien 44490075Sobrien layout_type (sjlj_fc_type_node); 44550397Sobrien 44690075Sobrien /* Cache the interesting field offsets so that we have 44790075Sobrien easy access from rtl. */ 44890075Sobrien sjlj_fc_call_site_ofs 44990075Sobrien = (tree_low_cst (DECL_FIELD_OFFSET (f_cs), 1) 45090075Sobrien + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_cs), 1) / BITS_PER_UNIT); 45190075Sobrien sjlj_fc_data_ofs 45290075Sobrien = (tree_low_cst (DECL_FIELD_OFFSET (f_data), 1) 45390075Sobrien + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_data), 1) / BITS_PER_UNIT); 45490075Sobrien sjlj_fc_personality_ofs 45590075Sobrien = (tree_low_cst (DECL_FIELD_OFFSET (f_per), 1) 45690075Sobrien + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_per), 1) / BITS_PER_UNIT); 45790075Sobrien sjlj_fc_lsda_ofs 45890075Sobrien = (tree_low_cst (DECL_FIELD_OFFSET (f_lsda), 1) 45990075Sobrien + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_lsda), 1) / BITS_PER_UNIT); 46090075Sobrien sjlj_fc_jbuf_ofs 46190075Sobrien = (tree_low_cst (DECL_FIELD_OFFSET (f_jbuf), 1) 46290075Sobrien + tree_low_cst (DECL_FIELD_BIT_OFFSET (f_jbuf), 1) / BITS_PER_UNIT); 46390075Sobrien } 46490075Sobrien} 46550397Sobrien 46690075Sobrienvoid 46790075Sobrieninit_eh_for_function () 46890075Sobrien{ 46990075Sobrien cfun->eh = (struct eh_status *) xcalloc (1, sizeof (struct eh_status)); 47090075Sobrien} 47150397Sobrien 47290075Sobrien/* Mark EH for GC. */ 47350397Sobrien 47490075Sobrienstatic void 47590075Sobrienmark_eh_region (region) 47690075Sobrien struct eh_region *region; 47790075Sobrien{ 47890075Sobrien if (! region) 47990075Sobrien return; 48050397Sobrien 48190075Sobrien switch (region->type) 48290075Sobrien { 48390075Sobrien case ERT_UNKNOWN: 48490075Sobrien /* This can happen if a nested function is inside the body of a region 48590075Sobrien and we do a GC as part of processing it. */ 48690075Sobrien break; 48790075Sobrien case ERT_CLEANUP: 48890075Sobrien ggc_mark_tree (region->u.cleanup.exp); 48990075Sobrien break; 49090075Sobrien case ERT_TRY: 49190075Sobrien ggc_mark_rtx (region->u.try.continue_label); 49290075Sobrien break; 49390075Sobrien case ERT_CATCH: 49490075Sobrien ggc_mark_tree (region->u.catch.type_list); 49590075Sobrien ggc_mark_tree (region->u.catch.filter_list); 49690075Sobrien break; 49790075Sobrien case ERT_ALLOWED_EXCEPTIONS: 49890075Sobrien ggc_mark_tree (region->u.allowed.type_list); 49990075Sobrien break; 50090075Sobrien case ERT_MUST_NOT_THROW: 50190075Sobrien break; 50290075Sobrien case ERT_THROW: 50390075Sobrien ggc_mark_tree (region->u.throw.type); 50490075Sobrien break; 50590075Sobrien case ERT_FIXUP: 50690075Sobrien ggc_mark_tree (region->u.fixup.cleanup_exp); 50790075Sobrien break; 50890075Sobrien default: 50990075Sobrien abort (); 51090075Sobrien } 51150397Sobrien 51290075Sobrien ggc_mark_rtx (region->label); 51390075Sobrien ggc_mark_rtx (region->resume); 51490075Sobrien ggc_mark_rtx (region->landing_pad); 51590075Sobrien ggc_mark_rtx (region->post_landing_pad); 51690075Sobrien} 51750397Sobrien 51890075Sobrienvoid 51990075Sobrienmark_eh_status (eh) 52090075Sobrien struct eh_status *eh; 52190075Sobrien{ 52290075Sobrien int i; 52350397Sobrien 52490075Sobrien if (eh == 0) 52590075Sobrien return; 52650397Sobrien 52790075Sobrien /* If we've called collect_eh_region_array, use it. Otherwise walk 52890075Sobrien the tree non-recursively. */ 52990075Sobrien if (eh->region_array) 53090075Sobrien { 53190075Sobrien for (i = eh->last_region_number; i > 0; --i) 53290075Sobrien { 53390075Sobrien struct eh_region *r = eh->region_array[i]; 53490075Sobrien if (r && r->region_number == i) 53590075Sobrien mark_eh_region (r); 53690075Sobrien } 53790075Sobrien } 53890075Sobrien else if (eh->region_tree) 53990075Sobrien { 54090075Sobrien struct eh_region *r = eh->region_tree; 54190075Sobrien while (1) 54290075Sobrien { 54390075Sobrien mark_eh_region (r); 54490075Sobrien if (r->inner) 54590075Sobrien r = r->inner; 54690075Sobrien else if (r->next_peer) 54790075Sobrien r = r->next_peer; 54890075Sobrien else 54990075Sobrien { 55090075Sobrien do { 55190075Sobrien r = r->outer; 55290075Sobrien if (r == NULL) 55390075Sobrien goto tree_done; 55490075Sobrien } while (r->next_peer == NULL); 55590075Sobrien r = r->next_peer; 55690075Sobrien } 55790075Sobrien } 55890075Sobrien tree_done:; 55990075Sobrien } 56050397Sobrien 56190075Sobrien ggc_mark_tree (eh->protect_list); 56290075Sobrien ggc_mark_rtx (eh->filter); 56390075Sobrien ggc_mark_rtx (eh->exc_ptr); 56490075Sobrien ggc_mark_tree_varray (eh->ttype_data); 56550397Sobrien 56690075Sobrien if (eh->call_site_data) 56790075Sobrien { 56890075Sobrien for (i = eh->call_site_data_used - 1; i >= 0; --i) 56990075Sobrien ggc_mark_rtx (eh->call_site_data[i].landing_pad); 57090075Sobrien } 57150397Sobrien 57290075Sobrien ggc_mark_rtx (eh->ehr_stackadj); 57390075Sobrien ggc_mark_rtx (eh->ehr_handler); 57490075Sobrien ggc_mark_rtx (eh->ehr_label); 57550397Sobrien 57690075Sobrien ggc_mark_rtx (eh->sjlj_fc); 57790075Sobrien ggc_mark_rtx (eh->sjlj_exit_after); 57890075Sobrien} 57950397Sobrien 58090075Sobrienvoid 58190075Sobrienfree_eh_status (f) 58290075Sobrien struct function *f; 58390075Sobrien{ 58490075Sobrien struct eh_status *eh = f->eh; 58550397Sobrien 58690075Sobrien if (eh->region_array) 58790075Sobrien { 58890075Sobrien int i; 58990075Sobrien for (i = eh->last_region_number; i > 0; --i) 59090075Sobrien { 59190075Sobrien struct eh_region *r = eh->region_array[i]; 59290075Sobrien /* Mind we don't free a region struct more than once. */ 59390075Sobrien if (r && r->region_number == i) 59490075Sobrien free (r); 59590075Sobrien } 59690075Sobrien free (eh->region_array); 59790075Sobrien } 59890075Sobrien else if (eh->region_tree) 59990075Sobrien { 60090075Sobrien struct eh_region *next, *r = eh->region_tree; 60190075Sobrien while (1) 60290075Sobrien { 60390075Sobrien if (r->inner) 60490075Sobrien r = r->inner; 60590075Sobrien else if (r->next_peer) 60690075Sobrien { 60790075Sobrien next = r->next_peer; 60890075Sobrien free (r); 60990075Sobrien r = next; 61090075Sobrien } 61190075Sobrien else 61290075Sobrien { 61390075Sobrien do { 61490075Sobrien next = r->outer; 61590075Sobrien free (r); 61690075Sobrien r = next; 61790075Sobrien if (r == NULL) 61890075Sobrien goto tree_done; 61990075Sobrien } while (r->next_peer == NULL); 62090075Sobrien next = r->next_peer; 62190075Sobrien free (r); 62290075Sobrien r = next; 62390075Sobrien } 62490075Sobrien } 62590075Sobrien tree_done:; 62690075Sobrien } 62750397Sobrien 62890075Sobrien VARRAY_FREE (eh->ttype_data); 62990075Sobrien VARRAY_FREE (eh->ehspec_data); 63090075Sobrien VARRAY_FREE (eh->action_record_data); 63190075Sobrien if (eh->call_site_data) 63290075Sobrien free (eh->call_site_data); 63350397Sobrien 63490075Sobrien free (eh); 63590075Sobrien f->eh = NULL; 63690075Sobrien exception_handler_labels = NULL; 63790075Sobrien} 63850397Sobrien 63990075Sobrien 64090075Sobrien/* Start an exception handling region. All instructions emitted 64190075Sobrien after this point are considered to be part of the region until 64290075Sobrien expand_eh_region_end is invoked. */ 64350397Sobrien 64490075Sobrienvoid 64590075Sobrienexpand_eh_region_start () 64690075Sobrien{ 64790075Sobrien struct eh_region *new_region; 64890075Sobrien struct eh_region *cur_region; 64990075Sobrien rtx note; 65052284Sobrien 65190075Sobrien if (! doing_eh (0)) 65290075Sobrien return; 65352284Sobrien 65490075Sobrien /* Insert a new blank region as a leaf in the tree. */ 65590075Sobrien new_region = (struct eh_region *) xcalloc (1, sizeof (*new_region)); 65690075Sobrien cur_region = cfun->eh->cur_region; 65790075Sobrien new_region->outer = cur_region; 65890075Sobrien if (cur_region) 65990075Sobrien { 66090075Sobrien new_region->next_peer = cur_region->inner; 66190075Sobrien cur_region->inner = new_region; 66290075Sobrien } 66390075Sobrien else 66490075Sobrien { 66590075Sobrien new_region->next_peer = cfun->eh->region_tree; 66690075Sobrien cfun->eh->region_tree = new_region; 66790075Sobrien } 66890075Sobrien cfun->eh->cur_region = new_region; 66952284Sobrien 67090075Sobrien /* Create a note marking the start of this region. */ 67190075Sobrien new_region->region_number = ++cfun->eh->last_region_number; 67290075Sobrien note = emit_note (NULL, NOTE_INSN_EH_REGION_BEG); 67390075Sobrien NOTE_EH_HANDLER (note) = new_region->region_number; 67490075Sobrien} 67552284Sobrien 67690075Sobrien/* Common code to end a region. Returns the region just ended. */ 67752284Sobrien 67890075Sobrienstatic struct eh_region * 67990075Sobrienexpand_eh_region_end () 68090075Sobrien{ 68190075Sobrien struct eh_region *cur_region = cfun->eh->cur_region; 68290075Sobrien rtx note; 68352284Sobrien 68490075Sobrien /* Create a note marking the end of this region. */ 68590075Sobrien note = emit_note (NULL, NOTE_INSN_EH_REGION_END); 68690075Sobrien NOTE_EH_HANDLER (note) = cur_region->region_number; 68752284Sobrien 68890075Sobrien /* Pop. */ 68990075Sobrien cfun->eh->cur_region = cur_region->outer; 69052284Sobrien 69190075Sobrien return cur_region; 69290075Sobrien} 69350397Sobrien 69490075Sobrien/* End an exception handling region for a cleanup. HANDLER is an 69590075Sobrien expression to expand for the cleanup. */ 69650397Sobrien 69790075Sobrienvoid 69890075Sobrienexpand_eh_region_end_cleanup (handler) 69990075Sobrien tree handler; 70052284Sobrien{ 70190075Sobrien struct eh_region *region; 70290075Sobrien tree protect_cleanup_actions; 70390075Sobrien rtx around_label; 70490075Sobrien rtx data_save[2]; 70552284Sobrien 70690075Sobrien if (! doing_eh (0)) 70790075Sobrien return; 70852284Sobrien 70990075Sobrien region = expand_eh_region_end (); 71090075Sobrien region->type = ERT_CLEANUP; 71190075Sobrien region->label = gen_label_rtx (); 71290075Sobrien region->u.cleanup.exp = handler; 71352284Sobrien 71490075Sobrien around_label = gen_label_rtx (); 71590075Sobrien emit_jump (around_label); 71652284Sobrien 71790075Sobrien emit_label (region->label); 71850397Sobrien 71990075Sobrien /* Give the language a chance to specify an action to be taken if an 72090075Sobrien exception is thrown that would propagate out of the HANDLER. */ 72190075Sobrien protect_cleanup_actions 72290075Sobrien = (lang_protect_cleanup_actions 72390075Sobrien ? (*lang_protect_cleanup_actions) () 72490075Sobrien : NULL_TREE); 72550397Sobrien 72690075Sobrien if (protect_cleanup_actions) 72790075Sobrien expand_eh_region_start (); 72850397Sobrien 72990075Sobrien /* In case this cleanup involves an inline destructor with a try block in 73090075Sobrien it, we need to save the EH return data registers around it. */ 73190075Sobrien data_save[0] = gen_reg_rtx (Pmode); 73290075Sobrien emit_move_insn (data_save[0], get_exception_pointer (cfun)); 73390075Sobrien data_save[1] = gen_reg_rtx (word_mode); 73490075Sobrien emit_move_insn (data_save[1], get_exception_filter (cfun)); 73550397Sobrien 73690075Sobrien expand_expr (handler, const0_rtx, VOIDmode, 0); 73750397Sobrien 73890075Sobrien emit_move_insn (cfun->eh->exc_ptr, data_save[0]); 73990075Sobrien emit_move_insn (cfun->eh->filter, data_save[1]); 74050397Sobrien 74190075Sobrien if (protect_cleanup_actions) 74290075Sobrien expand_eh_region_end_must_not_throw (protect_cleanup_actions); 74350397Sobrien 74490075Sobrien /* We need any stack adjustment complete before the around_label. */ 74590075Sobrien do_pending_stack_adjust (); 74690075Sobrien 74790075Sobrien /* We delay the generation of the _Unwind_Resume until we generate 74890075Sobrien landing pads. We emit a marker here so as to get good control 74990075Sobrien flow data in the meantime. */ 75090075Sobrien region->resume 75190075Sobrien = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number)); 75290075Sobrien emit_barrier (); 75390075Sobrien 75490075Sobrien emit_label (around_label); 75550397Sobrien} 75650397Sobrien 75790075Sobrien/* End an exception handling region for a try block, and prepares 75890075Sobrien for subsequent calls to expand_start_catch. */ 75950397Sobrien 76090075Sobrienvoid 76190075Sobrienexpand_start_all_catch () 76250397Sobrien{ 76390075Sobrien struct eh_region *region; 76450397Sobrien 76590075Sobrien if (! doing_eh (1)) 76690075Sobrien return; 76750397Sobrien 76890075Sobrien region = expand_eh_region_end (); 76990075Sobrien region->type = ERT_TRY; 77090075Sobrien region->u.try.prev_try = cfun->eh->try_region; 77190075Sobrien region->u.try.continue_label = gen_label_rtx (); 77250397Sobrien 77390075Sobrien cfun->eh->try_region = region; 77490075Sobrien 77590075Sobrien emit_jump (region->u.try.continue_label); 77650397Sobrien} 77750397Sobrien 77890075Sobrien/* Begin a catch clause. TYPE is the type caught, a list of such types, or 77990075Sobrien null if this is a catch-all clause. Providing a type list enables to 78090075Sobrien associate the catch region with potentially several exception types, which 78190075Sobrien is useful e.g. for Ada. */ 78250397Sobrien 78390075Sobrienvoid 78490075Sobrienexpand_start_catch (type_or_list) 78590075Sobrien tree type_or_list; 78650397Sobrien{ 78790075Sobrien struct eh_region *t, *c, *l; 78890075Sobrien tree type_list; 78950397Sobrien 79090075Sobrien if (! doing_eh (0)) 79190075Sobrien return; 79290075Sobrien 79390075Sobrien type_list = type_or_list; 79490075Sobrien 79590075Sobrien if (type_or_list) 79690075Sobrien { 79790075Sobrien /* Ensure to always end up with a type list to normalize further 79890075Sobrien processing, then register each type against the runtime types 79990075Sobrien map. */ 80090075Sobrien tree type_node; 80190075Sobrien 80290075Sobrien if (TREE_CODE (type_or_list) != TREE_LIST) 80390075Sobrien type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE); 80490075Sobrien 80590075Sobrien type_node = type_list; 80690075Sobrien for (; type_node; type_node = TREE_CHAIN (type_node)) 80790075Sobrien add_type_for_runtime (TREE_VALUE (type_node)); 80890075Sobrien } 80990075Sobrien 81090075Sobrien expand_eh_region_start (); 81190075Sobrien 81290075Sobrien t = cfun->eh->try_region; 81390075Sobrien c = cfun->eh->cur_region; 81490075Sobrien c->type = ERT_CATCH; 81590075Sobrien c->u.catch.type_list = type_list; 81690075Sobrien c->label = gen_label_rtx (); 81790075Sobrien 81890075Sobrien l = t->u.try.last_catch; 81990075Sobrien c->u.catch.prev_catch = l; 82090075Sobrien if (l) 82190075Sobrien l->u.catch.next_catch = c; 82252284Sobrien else 82390075Sobrien t->u.try.catch = c; 82490075Sobrien t->u.try.last_catch = c; 82550397Sobrien 82690075Sobrien emit_label (c->label); 82750397Sobrien} 82850397Sobrien 82990075Sobrien/* End a catch clause. Control will resume after the try/catch block. */ 83090075Sobrien 83190075Sobrienvoid 83290075Sobrienexpand_end_catch () 83350397Sobrien{ 83490075Sobrien struct eh_region *try_region, *catch_region; 83550397Sobrien 83690075Sobrien if (! doing_eh (0)) 83790075Sobrien return; 83850397Sobrien 83990075Sobrien catch_region = expand_eh_region_end (); 84090075Sobrien try_region = cfun->eh->try_region; 84150397Sobrien 84290075Sobrien emit_jump (try_region->u.try.continue_label); 84350397Sobrien} 84450397Sobrien 84590075Sobrien/* End a sequence of catch handlers for a try block. */ 84650397Sobrien 84790075Sobrienvoid 84890075Sobrienexpand_end_all_catch () 84950397Sobrien{ 85090075Sobrien struct eh_region *try_region; 85150397Sobrien 85290075Sobrien if (! doing_eh (0)) 85390075Sobrien return; 85450397Sobrien 85590075Sobrien try_region = cfun->eh->try_region; 85690075Sobrien cfun->eh->try_region = try_region->u.try.prev_try; 85790075Sobrien 85890075Sobrien emit_label (try_region->u.try.continue_label); 85950397Sobrien} 86050397Sobrien 86190075Sobrien/* End an exception region for an exception type filter. ALLOWED is a 86290075Sobrien TREE_LIST of types to be matched by the runtime. FAILURE is an 86390075Sobrien expression to invoke if a mismatch occurs. 86450397Sobrien 86590075Sobrien ??? We could use these semantics for calls to rethrow, too; if we can 86690075Sobrien see the surrounding catch clause, we know that the exception we're 86790075Sobrien rethrowing satisfies the "filter" of the catch type. */ 86890075Sobrien 86990075Sobrienvoid 87090075Sobrienexpand_eh_region_end_allowed (allowed, failure) 87190075Sobrien tree allowed, failure; 87250397Sobrien{ 87390075Sobrien struct eh_region *region; 87490075Sobrien rtx around_label; 87550397Sobrien 87690075Sobrien if (! doing_eh (0)) 87790075Sobrien return; 87850397Sobrien 87990075Sobrien region = expand_eh_region_end (); 88090075Sobrien region->type = ERT_ALLOWED_EXCEPTIONS; 88190075Sobrien region->u.allowed.type_list = allowed; 88290075Sobrien region->label = gen_label_rtx (); 88350397Sobrien 88490075Sobrien for (; allowed ; allowed = TREE_CHAIN (allowed)) 88590075Sobrien add_type_for_runtime (TREE_VALUE (allowed)); 88650397Sobrien 88790075Sobrien /* We must emit the call to FAILURE here, so that if this function 88890075Sobrien throws a different exception, that it will be processed by the 88990075Sobrien correct region. */ 89090075Sobrien 89190075Sobrien around_label = gen_label_rtx (); 89290075Sobrien emit_jump (around_label); 89390075Sobrien 89490075Sobrien emit_label (region->label); 89590075Sobrien expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL); 89690075Sobrien /* We must adjust the stack before we reach the AROUND_LABEL because 89790075Sobrien the call to FAILURE does not occur on all paths to the 89890075Sobrien AROUND_LABEL. */ 89990075Sobrien do_pending_stack_adjust (); 90090075Sobrien 90190075Sobrien emit_label (around_label); 90250397Sobrien} 90350397Sobrien 90490075Sobrien/* End an exception region for a must-not-throw filter. FAILURE is an 90590075Sobrien expression invoke if an uncaught exception propagates this far. 90690075Sobrien 90790075Sobrien This is conceptually identical to expand_eh_region_end_allowed with 90890075Sobrien an empty allowed list (if you passed "std::terminate" instead of 90990075Sobrien "__cxa_call_unexpected"), but they are represented differently in 91090075Sobrien the C++ LSDA. */ 91190075Sobrien 91290075Sobrienvoid 91390075Sobrienexpand_eh_region_end_must_not_throw (failure) 91490075Sobrien tree failure; 91550397Sobrien{ 91690075Sobrien struct eh_region *region; 91790075Sobrien rtx around_label; 91874722Sobrien 91990075Sobrien if (! doing_eh (0)) 92090075Sobrien return; 92174722Sobrien 92290075Sobrien region = expand_eh_region_end (); 92390075Sobrien region->type = ERT_MUST_NOT_THROW; 92490075Sobrien region->label = gen_label_rtx (); 92574722Sobrien 92690075Sobrien /* We must emit the call to FAILURE here, so that if this function 92790075Sobrien throws a different exception, that it will be processed by the 92890075Sobrien correct region. */ 92990075Sobrien 93090075Sobrien around_label = gen_label_rtx (); 93190075Sobrien emit_jump (around_label); 93290075Sobrien 93390075Sobrien emit_label (region->label); 93490075Sobrien expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL); 93590075Sobrien 93690075Sobrien emit_label (around_label); 93750397Sobrien} 93850397Sobrien 93990075Sobrien/* End an exception region for a throw. No handling goes on here, 94090075Sobrien but it's the easiest way for the front-end to indicate what type 94190075Sobrien is being thrown. */ 94290075Sobrien 94390075Sobrienvoid 94490075Sobrienexpand_eh_region_end_throw (type) 94590075Sobrien tree type; 94650397Sobrien{ 94790075Sobrien struct eh_region *region; 94850397Sobrien 94990075Sobrien if (! doing_eh (0)) 95090075Sobrien return; 95150397Sobrien 95290075Sobrien region = expand_eh_region_end (); 95390075Sobrien region->type = ERT_THROW; 95490075Sobrien region->u.throw.type = type; 95590075Sobrien} 95650397Sobrien 95790075Sobrien/* End a fixup region. Within this region the cleanups for the immediately 95890075Sobrien enclosing region are _not_ run. This is used for goto cleanup to avoid 95990075Sobrien destroying an object twice. 96050397Sobrien 96190075Sobrien This would be an extraordinarily simple prospect, were it not for the 96290075Sobrien fact that we don't actually know what the immediately enclosing region 96390075Sobrien is. This surprising fact is because expand_cleanups is currently 96490075Sobrien generating a sequence that it will insert somewhere else. We collect 96590075Sobrien the proper notion of "enclosing" in convert_from_eh_region_ranges. */ 96650397Sobrien 96790075Sobrienvoid 96890075Sobrienexpand_eh_region_end_fixup (handler) 96990075Sobrien tree handler; 97050397Sobrien{ 97190075Sobrien struct eh_region *fixup; 97250397Sobrien 97390075Sobrien if (! doing_eh (0)) 97490075Sobrien return; 97590075Sobrien 97690075Sobrien fixup = expand_eh_region_end (); 97790075Sobrien fixup->type = ERT_FIXUP; 97890075Sobrien fixup->u.fixup.cleanup_exp = handler; 97950397Sobrien} 98050397Sobrien 98190075Sobrien/* Return an rtl expression for a pointer to the exception object 98290075Sobrien within a handler. */ 98350397Sobrien 98490075Sobrienrtx 98590075Sobrienget_exception_pointer (fun) 98690075Sobrien struct function *fun; 98750397Sobrien{ 98890075Sobrien rtx exc_ptr = fun->eh->exc_ptr; 98990075Sobrien if (fun == cfun && ! exc_ptr) 99050397Sobrien { 99190075Sobrien exc_ptr = gen_reg_rtx (Pmode); 99290075Sobrien fun->eh->exc_ptr = exc_ptr; 99350397Sobrien } 99490075Sobrien return exc_ptr; 99550397Sobrien} 99650397Sobrien 99790075Sobrien/* Return an rtl expression for the exception dispatch filter 99890075Sobrien within a handler. */ 99950397Sobrien 100090075Sobrienstatic rtx 100190075Sobrienget_exception_filter (fun) 100290075Sobrien struct function *fun; 100350397Sobrien{ 100490075Sobrien rtx filter = fun->eh->filter; 100590075Sobrien if (fun == cfun && ! filter) 100650397Sobrien { 100790075Sobrien filter = gen_reg_rtx (word_mode); 100890075Sobrien fun->eh->filter = filter; 100950397Sobrien } 101090075Sobrien return filter; 101150397Sobrien} 101290075Sobrien 101390075Sobrien/* Begin a region that will contain entries created with 101490075Sobrien add_partial_entry. */ 101550397Sobrien 101690075Sobrienvoid 101790075Sobrienbegin_protect_partials () 101850397Sobrien{ 101990075Sobrien /* Push room for a new list. */ 102090075Sobrien cfun->eh->protect_list 102190075Sobrien = tree_cons (NULL_TREE, NULL_TREE, cfun->eh->protect_list); 102290075Sobrien} 102350397Sobrien 102490075Sobrien/* Start a new exception region for a region of code that has a 102590075Sobrien cleanup action and push the HANDLER for the region onto 102690075Sobrien protect_list. All of the regions created with add_partial_entry 102790075Sobrien will be ended when end_protect_partials is invoked. 102850397Sobrien 102990075Sobrien ??? The only difference between this purpose and that of 103090075Sobrien expand_decl_cleanup is that in this case, we only want the cleanup to 103190075Sobrien run if an exception is thrown. This should also be handled using 103290075Sobrien binding levels. */ 103350397Sobrien 103490075Sobrienvoid 103590075Sobrienadd_partial_entry (handler) 103690075Sobrien tree handler; 103790075Sobrien{ 103890075Sobrien expand_eh_region_start (); 103950397Sobrien 104090075Sobrien /* Add this entry to the front of the list. */ 104190075Sobrien TREE_VALUE (cfun->eh->protect_list) 104290075Sobrien = tree_cons (NULL_TREE, handler, TREE_VALUE (cfun->eh->protect_list)); 104390075Sobrien} 104450397Sobrien 104590075Sobrien/* End all the pending exception regions on protect_list. */ 104650397Sobrien 104790075Sobrienvoid 104890075Sobrienend_protect_partials () 104990075Sobrien{ 105090075Sobrien tree t; 105150397Sobrien 105290075Sobrien /* Pop the topmost entry. */ 105390075Sobrien t = TREE_VALUE (cfun->eh->protect_list); 105490075Sobrien cfun->eh->protect_list = TREE_CHAIN (cfun->eh->protect_list); 105590075Sobrien 105690075Sobrien /* End all the exception regions. */ 105790075Sobrien for (; t; t = TREE_CHAIN (t)) 105890075Sobrien expand_eh_region_end_cleanup (TREE_VALUE (t)); 105950397Sobrien} 106050397Sobrien 106190075Sobrien 106290075Sobrien/* This section is for the exception handling specific optimization pass. */ 106350397Sobrien 106490075Sobrien/* Random access the exception region tree. It's just as simple to 106590075Sobrien collect the regions this way as in expand_eh_region_start, but 106690075Sobrien without having to realloc memory. */ 106790075Sobrien 106890075Sobrienstatic void 106990075Sobriencollect_eh_region_array () 107050397Sobrien{ 107190075Sobrien struct eh_region **array, *i; 107250397Sobrien 107390075Sobrien i = cfun->eh->region_tree; 107490075Sobrien if (! i) 107590075Sobrien return; 107650397Sobrien 107790075Sobrien array = xcalloc (cfun->eh->last_region_number + 1, sizeof (*array)); 107890075Sobrien cfun->eh->region_array = array; 107950397Sobrien 108090075Sobrien while (1) 108190075Sobrien { 108290075Sobrien array[i->region_number] = i; 108350397Sobrien 108490075Sobrien /* If there are sub-regions, process them. */ 108590075Sobrien if (i->inner) 108690075Sobrien i = i->inner; 108790075Sobrien /* If there are peers, process them. */ 108890075Sobrien else if (i->next_peer) 108990075Sobrien i = i->next_peer; 109090075Sobrien /* Otherwise, step back up the tree to the next peer. */ 109190075Sobrien else 109290075Sobrien { 109390075Sobrien do { 109490075Sobrien i = i->outer; 109590075Sobrien if (i == NULL) 109690075Sobrien return; 109790075Sobrien } while (i->next_peer == NULL); 109890075Sobrien i = i->next_peer; 109990075Sobrien } 110090075Sobrien } 110190075Sobrien} 110250397Sobrien 110390075Sobrienstatic void 110490075Sobrienresolve_fixup_regions () 110550397Sobrien{ 110690075Sobrien int i, j, n = cfun->eh->last_region_number; 110750397Sobrien 110890075Sobrien for (i = 1; i <= n; ++i) 110990075Sobrien { 111090075Sobrien struct eh_region *fixup = cfun->eh->region_array[i]; 111190075Sobrien struct eh_region *cleanup = 0; 111250397Sobrien 111390075Sobrien if (! fixup || fixup->type != ERT_FIXUP) 111490075Sobrien continue; 111550397Sobrien 111690075Sobrien for (j = 1; j <= n; ++j) 111790075Sobrien { 111890075Sobrien cleanup = cfun->eh->region_array[j]; 111990075Sobrien if (cleanup->type == ERT_CLEANUP 112090075Sobrien && cleanup->u.cleanup.exp == fixup->u.fixup.cleanup_exp) 112190075Sobrien break; 112290075Sobrien } 112390075Sobrien if (j > n) 112490075Sobrien abort (); 112590075Sobrien 112690075Sobrien fixup->u.fixup.real_region = cleanup->outer; 112790075Sobrien } 112850397Sobrien} 112950397Sobrien 113090075Sobrien/* Now that we've discovered what region actually encloses a fixup, 113190075Sobrien we can shuffle pointers and remove them from the tree. */ 113250397Sobrien 113350397Sobrienstatic void 113490075Sobrienremove_fixup_regions () 113550397Sobrien{ 113690075Sobrien int i; 113790075Sobrien rtx insn, note; 113890075Sobrien struct eh_region *fixup; 113990075Sobrien 114090075Sobrien /* Walk the insn chain and adjust the REG_EH_REGION numbers 114190075Sobrien for instructions referencing fixup regions. This is only 114290075Sobrien strictly necessary for fixup regions with no parent, but 114390075Sobrien doesn't hurt to do it for all regions. */ 114490075Sobrien for (insn = get_insns(); insn ; insn = NEXT_INSN (insn)) 114590075Sobrien if (INSN_P (insn) 114690075Sobrien && (note = find_reg_note (insn, REG_EH_REGION, NULL)) 114790075Sobrien && INTVAL (XEXP (note, 0)) > 0 114890075Sobrien && (fixup = cfun->eh->region_array[INTVAL (XEXP (note, 0))]) 114990075Sobrien && fixup->type == ERT_FIXUP) 115050397Sobrien { 115190075Sobrien if (fixup->u.fixup.real_region) 115290075Sobrien XEXP (note, 0) = GEN_INT (fixup->u.fixup.real_region->region_number); 115390075Sobrien else 115490075Sobrien remove_note (insn, note); 115550397Sobrien } 115650397Sobrien 115790075Sobrien /* Remove the fixup regions from the tree. */ 115890075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 115990075Sobrien { 116090075Sobrien fixup = cfun->eh->region_array[i]; 116190075Sobrien if (! fixup) 116290075Sobrien continue; 116350397Sobrien 116490075Sobrien /* Allow GC to maybe free some memory. */ 116590075Sobrien if (fixup->type == ERT_CLEANUP) 116690075Sobrien fixup->u.cleanup.exp = NULL_TREE; 116750397Sobrien 116890075Sobrien if (fixup->type != ERT_FIXUP) 116990075Sobrien continue; 117050397Sobrien 117190075Sobrien if (fixup->inner) 117290075Sobrien { 117390075Sobrien struct eh_region *parent, *p, **pp; 117450397Sobrien 117590075Sobrien parent = fixup->u.fixup.real_region; 117652284Sobrien 117790075Sobrien /* Fix up the children's parent pointers; find the end of 117890075Sobrien the list. */ 117990075Sobrien for (p = fixup->inner; ; p = p->next_peer) 118090075Sobrien { 118190075Sobrien p->outer = parent; 118290075Sobrien if (! p->next_peer) 118390075Sobrien break; 118490075Sobrien } 118550397Sobrien 118690075Sobrien /* In the tree of cleanups, only outer-inner ordering matters. 118790075Sobrien So link the children back in anywhere at the correct level. */ 118890075Sobrien if (parent) 118990075Sobrien pp = &parent->inner; 119090075Sobrien else 119190075Sobrien pp = &cfun->eh->region_tree; 119290075Sobrien p->next_peer = *pp; 119390075Sobrien *pp = fixup->inner; 119490075Sobrien fixup->inner = NULL; 119590075Sobrien } 119690075Sobrien 119790075Sobrien remove_eh_handler (fixup); 119850397Sobrien } 119950397Sobrien} 120050397Sobrien 120190075Sobrien/* Remove all regions whose labels are not reachable from insns. */ 120252284Sobrien 120390075Sobrienstatic void 120490075Sobrienremove_unreachable_regions (insns) 120590075Sobrien rtx insns; 120652284Sobrien{ 120790075Sobrien int i, *uid_region_num; 120890075Sobrien bool *reachable; 120990075Sobrien struct eh_region *r; 121090075Sobrien rtx insn; 121152284Sobrien 121290075Sobrien uid_region_num = xcalloc (get_max_uid (), sizeof(int)); 121390075Sobrien reachable = xcalloc (cfun->eh->last_region_number + 1, sizeof(bool)); 121452284Sobrien 121590075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 121690075Sobrien { 121790075Sobrien r = cfun->eh->region_array[i]; 121890075Sobrien if (!r || r->region_number != i) 121990075Sobrien continue; 122052284Sobrien 122190075Sobrien if (r->resume) 122290075Sobrien { 122390075Sobrien if (uid_region_num[INSN_UID (r->resume)]) 122490075Sobrien abort (); 122590075Sobrien uid_region_num[INSN_UID (r->resume)] = i; 122690075Sobrien } 122790075Sobrien if (r->label) 122890075Sobrien { 122990075Sobrien if (uid_region_num[INSN_UID (r->label)]) 123090075Sobrien abort (); 123190075Sobrien uid_region_num[INSN_UID (r->label)] = i; 123290075Sobrien } 123390075Sobrien if (r->type == ERT_TRY && r->u.try.continue_label) 123490075Sobrien { 123590075Sobrien if (uid_region_num[INSN_UID (r->u.try.continue_label)]) 123690075Sobrien abort (); 123790075Sobrien uid_region_num[INSN_UID (r->u.try.continue_label)] = i; 123890075Sobrien } 123952284Sobrien } 124052284Sobrien 124190075Sobrien for (insn = insns; insn; insn = NEXT_INSN (insn)) 124290075Sobrien reachable[uid_region_num[INSN_UID (insn)]] = true; 124350397Sobrien 124490075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 124550397Sobrien { 124690075Sobrien r = cfun->eh->region_array[i]; 124790075Sobrien if (r && r->region_number == i && !reachable[i]) 124850397Sobrien { 124990075Sobrien /* Don't remove ERT_THROW regions if their outer region 125090075Sobrien is reachable. */ 125190075Sobrien if (r->type == ERT_THROW 125290075Sobrien && r->outer 125390075Sobrien && reachable[r->outer->region_number]) 125490075Sobrien continue; 125590075Sobrien 125690075Sobrien remove_eh_handler (r); 125750397Sobrien } 125850397Sobrien } 125990075Sobrien 126090075Sobrien free (reachable); 126190075Sobrien free (uid_region_num); 126250397Sobrien} 126350397Sobrien 126490075Sobrien/* Turn NOTE_INSN_EH_REGION notes into REG_EH_REGION notes for each 126590075Sobrien can_throw instruction in the region. */ 126650397Sobrien 126790075Sobrienstatic void 126890075Sobrienconvert_from_eh_region_ranges_1 (pinsns, orig_sp, cur) 126990075Sobrien rtx *pinsns; 127090075Sobrien int *orig_sp; 127190075Sobrien int cur; 127250397Sobrien{ 127390075Sobrien int *sp = orig_sp; 127490075Sobrien rtx insn, next; 127550397Sobrien 127690075Sobrien for (insn = *pinsns; insn ; insn = next) 127790075Sobrien { 127890075Sobrien next = NEXT_INSN (insn); 127990075Sobrien if (GET_CODE (insn) == NOTE) 128090075Sobrien { 128190075Sobrien int kind = NOTE_LINE_NUMBER (insn); 128290075Sobrien if (kind == NOTE_INSN_EH_REGION_BEG 128390075Sobrien || kind == NOTE_INSN_EH_REGION_END) 128490075Sobrien { 128590075Sobrien if (kind == NOTE_INSN_EH_REGION_BEG) 128690075Sobrien { 128790075Sobrien struct eh_region *r; 128850397Sobrien 128990075Sobrien *sp++ = cur; 129090075Sobrien cur = NOTE_EH_HANDLER (insn); 129150397Sobrien 129290075Sobrien r = cfun->eh->region_array[cur]; 129390075Sobrien if (r->type == ERT_FIXUP) 129490075Sobrien { 129590075Sobrien r = r->u.fixup.real_region; 129690075Sobrien cur = r ? r->region_number : 0; 129790075Sobrien } 129890075Sobrien else if (r->type == ERT_CATCH) 129990075Sobrien { 130090075Sobrien r = r->outer; 130190075Sobrien cur = r ? r->region_number : 0; 130290075Sobrien } 130390075Sobrien } 130490075Sobrien else 130590075Sobrien cur = *--sp; 130650397Sobrien 130790075Sobrien /* Removing the first insn of a CALL_PLACEHOLDER sequence 130890075Sobrien requires extra care to adjust sequence start. */ 130990075Sobrien if (insn == *pinsns) 131090075Sobrien *pinsns = next; 131190075Sobrien remove_insn (insn); 131290075Sobrien continue; 131390075Sobrien } 131490075Sobrien } 131590075Sobrien else if (INSN_P (insn)) 131690075Sobrien { 131790075Sobrien if (cur > 0 131890075Sobrien && ! find_reg_note (insn, REG_EH_REGION, NULL_RTX) 131990075Sobrien /* Calls can always potentially throw exceptions, unless 132090075Sobrien they have a REG_EH_REGION note with a value of 0 or less. 132190075Sobrien Which should be the only possible kind so far. */ 132290075Sobrien && (GET_CODE (insn) == CALL_INSN 132390075Sobrien /* If we wanted exceptions for non-call insns, then 132490075Sobrien any may_trap_p instruction could throw. */ 132590075Sobrien || (flag_non_call_exceptions 132690075Sobrien && GET_CODE (PATTERN (insn)) != CLOBBER 132790075Sobrien && GET_CODE (PATTERN (insn)) != USE 132890075Sobrien && may_trap_p (PATTERN (insn))))) 132990075Sobrien { 133090075Sobrien REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION, GEN_INT (cur), 133190075Sobrien REG_NOTES (insn)); 133290075Sobrien } 133350397Sobrien 133490075Sobrien if (GET_CODE (insn) == CALL_INSN 133590075Sobrien && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) 133690075Sobrien { 133790075Sobrien convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 0), 133890075Sobrien sp, cur); 133990075Sobrien convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 1), 134090075Sobrien sp, cur); 134190075Sobrien convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 2), 134290075Sobrien sp, cur); 134390075Sobrien } 134490075Sobrien } 134590075Sobrien } 134650397Sobrien 134790075Sobrien if (sp != orig_sp) 134890075Sobrien abort (); 134950397Sobrien} 135050397Sobrien 135190075Sobrienvoid 135290075Sobrienconvert_from_eh_region_ranges () 135350397Sobrien{ 135490075Sobrien int *stack; 135590075Sobrien rtx insns; 135650397Sobrien 135790075Sobrien collect_eh_region_array (); 135890075Sobrien resolve_fixup_regions (); 135950397Sobrien 136090075Sobrien stack = xmalloc (sizeof (int) * (cfun->eh->last_region_number + 1)); 136190075Sobrien insns = get_insns (); 136290075Sobrien convert_from_eh_region_ranges_1 (&insns, stack, 0); 136390075Sobrien free (stack); 136450397Sobrien 136590075Sobrien remove_fixup_regions (); 136690075Sobrien remove_unreachable_regions (insns); 136750397Sobrien} 136850397Sobrien 136990075Sobrienvoid 137090075Sobrienfind_exception_handler_labels () 137190075Sobrien{ 137290075Sobrien rtx list = NULL_RTX; 137390075Sobrien int i; 137450397Sobrien 137590075Sobrien free_EXPR_LIST_list (&exception_handler_labels); 137650397Sobrien 137790075Sobrien if (cfun->eh->region_tree == NULL) 137890075Sobrien return; 137990075Sobrien 138090075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 138150397Sobrien { 138290075Sobrien struct eh_region *region = cfun->eh->region_array[i]; 138390075Sobrien rtx lab; 138450397Sobrien 138590075Sobrien if (! region || region->region_number != i) 138690075Sobrien continue; 138790075Sobrien if (cfun->eh->built_landing_pads) 138890075Sobrien lab = region->landing_pad; 138990075Sobrien else 139090075Sobrien lab = region->label; 139150397Sobrien 139290075Sobrien if (lab) 139390075Sobrien list = alloc_EXPR_LIST (0, lab, list); 139450397Sobrien } 139590075Sobrien 139690075Sobrien /* For sjlj exceptions, need the return label to remain live until 139790075Sobrien after landing pad generation. */ 139890075Sobrien if (USING_SJLJ_EXCEPTIONS && ! cfun->eh->built_landing_pads) 139990075Sobrien list = alloc_EXPR_LIST (0, return_label, list); 140090075Sobrien 140190075Sobrien exception_handler_labels = list; 140250397Sobrien} 140350397Sobrien 140490075Sobrien 140590075Sobrienstatic struct eh_region * 140690075Sobrienduplicate_eh_region_1 (o, map) 140790075Sobrien struct eh_region *o; 140890075Sobrien struct inline_remap *map; 140950397Sobrien{ 141090075Sobrien struct eh_region *n 141190075Sobrien = (struct eh_region *) xcalloc (1, sizeof (struct eh_region)); 141250397Sobrien 141390075Sobrien n->region_number = o->region_number + cfun->eh->last_region_number; 141490075Sobrien n->type = o->type; 141550397Sobrien 141690075Sobrien switch (n->type) 141790075Sobrien { 141890075Sobrien case ERT_CLEANUP: 141990075Sobrien case ERT_MUST_NOT_THROW: 142090075Sobrien break; 142150397Sobrien 142290075Sobrien case ERT_TRY: 142390075Sobrien if (o->u.try.continue_label) 142490075Sobrien n->u.try.continue_label 142590075Sobrien = get_label_from_map (map, 142690075Sobrien CODE_LABEL_NUMBER (o->u.try.continue_label)); 142790075Sobrien break; 142850397Sobrien 142990075Sobrien case ERT_CATCH: 143090075Sobrien n->u.catch.type_list = o->u.catch.type_list; 143190075Sobrien break; 143250397Sobrien 143390075Sobrien case ERT_ALLOWED_EXCEPTIONS: 143490075Sobrien n->u.allowed.type_list = o->u.allowed.type_list; 143590075Sobrien break; 143650397Sobrien 143790075Sobrien case ERT_THROW: 143890075Sobrien n->u.throw.type = o->u.throw.type; 143950397Sobrien 144090075Sobrien default: 144190075Sobrien abort (); 144290075Sobrien } 144350397Sobrien 144490075Sobrien if (o->label) 144590075Sobrien n->label = get_label_from_map (map, CODE_LABEL_NUMBER (o->label)); 144690075Sobrien if (o->resume) 144790075Sobrien { 144890075Sobrien n->resume = map->insn_map[INSN_UID (o->resume)]; 144990075Sobrien if (n->resume == NULL) 145090075Sobrien abort (); 145190075Sobrien } 145250397Sobrien 145390075Sobrien return n; 145450397Sobrien} 145550397Sobrien 145650397Sobrienstatic void 145790075Sobrienduplicate_eh_region_2 (o, n_array) 145890075Sobrien struct eh_region *o; 145990075Sobrien struct eh_region **n_array; 146050397Sobrien{ 146190075Sobrien struct eh_region *n = n_array[o->region_number]; 146250397Sobrien 146390075Sobrien switch (n->type) 146490075Sobrien { 146590075Sobrien case ERT_TRY: 146690075Sobrien n->u.try.catch = n_array[o->u.try.catch->region_number]; 146790075Sobrien n->u.try.last_catch = n_array[o->u.try.last_catch->region_number]; 146890075Sobrien break; 146950397Sobrien 147090075Sobrien case ERT_CATCH: 147190075Sobrien if (o->u.catch.next_catch) 147290075Sobrien n->u.catch.next_catch = n_array[o->u.catch.next_catch->region_number]; 147390075Sobrien if (o->u.catch.prev_catch) 147490075Sobrien n->u.catch.prev_catch = n_array[o->u.catch.prev_catch->region_number]; 147590075Sobrien break; 147650397Sobrien 147790075Sobrien default: 147890075Sobrien break; 147990075Sobrien } 148090075Sobrien 148190075Sobrien if (o->outer) 148290075Sobrien n->outer = n_array[o->outer->region_number]; 148390075Sobrien if (o->inner) 148490075Sobrien n->inner = n_array[o->inner->region_number]; 148590075Sobrien if (o->next_peer) 148690075Sobrien n->next_peer = n_array[o->next_peer->region_number]; 148790075Sobrien} 148890075Sobrien 148990075Sobrienint 149090075Sobrienduplicate_eh_regions (ifun, map) 149190075Sobrien struct function *ifun; 149290075Sobrien struct inline_remap *map; 149350397Sobrien{ 149490075Sobrien int ifun_last_region_number = ifun->eh->last_region_number; 149590075Sobrien struct eh_region **n_array, *root, *cur; 149690075Sobrien int i; 149750397Sobrien 149890075Sobrien if (ifun_last_region_number == 0) 149990075Sobrien return 0; 150050397Sobrien 150190075Sobrien n_array = xcalloc (ifun_last_region_number + 1, sizeof (*n_array)); 150250397Sobrien 150390075Sobrien for (i = 1; i <= ifun_last_region_number; ++i) 150490075Sobrien { 150590075Sobrien cur = ifun->eh->region_array[i]; 150690075Sobrien if (!cur || cur->region_number != i) 150790075Sobrien continue; 150890075Sobrien n_array[i] = duplicate_eh_region_1 (cur, map); 150990075Sobrien } 151090075Sobrien for (i = 1; i <= ifun_last_region_number; ++i) 151190075Sobrien { 151290075Sobrien cur = ifun->eh->region_array[i]; 151390075Sobrien if (!cur || cur->region_number != i) 151490075Sobrien continue; 151590075Sobrien duplicate_eh_region_2 (cur, n_array); 151690075Sobrien } 151750397Sobrien 151890075Sobrien root = n_array[ifun->eh->region_tree->region_number]; 151990075Sobrien cur = cfun->eh->cur_region; 152090075Sobrien if (cur) 152190075Sobrien { 152290075Sobrien struct eh_region *p = cur->inner; 152390075Sobrien if (p) 152490075Sobrien { 152590075Sobrien while (p->next_peer) 152690075Sobrien p = p->next_peer; 152790075Sobrien p->next_peer = root; 152890075Sobrien } 152990075Sobrien else 153090075Sobrien cur->inner = root; 153150397Sobrien 153290075Sobrien for (i = 1; i <= ifun_last_region_number; ++i) 153390075Sobrien if (n_array[i] && n_array[i]->outer == NULL) 153490075Sobrien n_array[i]->outer = cur; 153590075Sobrien } 153690075Sobrien else 153790075Sobrien { 153890075Sobrien struct eh_region *p = cfun->eh->region_tree; 153990075Sobrien if (p) 154090075Sobrien { 154190075Sobrien while (p->next_peer) 154290075Sobrien p = p->next_peer; 154390075Sobrien p->next_peer = root; 154490075Sobrien } 154590075Sobrien else 154690075Sobrien cfun->eh->region_tree = root; 154790075Sobrien } 154850397Sobrien 154990075Sobrien free (n_array); 155050397Sobrien 155190075Sobrien i = cfun->eh->last_region_number; 155290075Sobrien cfun->eh->last_region_number = i + ifun_last_region_number; 155390075Sobrien return i; 155490075Sobrien} 155550397Sobrien 155690075Sobrien 155790075Sobrienstatic int 155890075Sobrient2r_eq (pentry, pdata) 155990075Sobrien const PTR pentry; 156090075Sobrien const PTR pdata; 156190075Sobrien{ 156290075Sobrien tree entry = (tree) pentry; 156390075Sobrien tree data = (tree) pdata; 156450397Sobrien 156590075Sobrien return TREE_PURPOSE (entry) == data; 156690075Sobrien} 156750397Sobrien 156890075Sobrienstatic hashval_t 156990075Sobrient2r_hash (pentry) 157090075Sobrien const PTR pentry; 157190075Sobrien{ 157290075Sobrien tree entry = (tree) pentry; 157390075Sobrien return TYPE_HASH (TREE_PURPOSE (entry)); 157450397Sobrien} 157550397Sobrien 157690075Sobrienstatic int 157790075Sobrient2r_mark_1 (slot, data) 157890075Sobrien PTR *slot; 157990075Sobrien PTR data ATTRIBUTE_UNUSED; 158090075Sobrien{ 158190075Sobrien tree contents = (tree) *slot; 158290075Sobrien ggc_mark_tree (contents); 158390075Sobrien return 1; 158490075Sobrien} 158550397Sobrien 158650397Sobrienstatic void 158790075Sobrient2r_mark (addr) 158890075Sobrien PTR addr; 158950397Sobrien{ 159090075Sobrien htab_traverse (*(htab_t *)addr, t2r_mark_1, NULL); 159190075Sobrien} 159250397Sobrien 159390075Sobrienstatic void 159490075Sobrienadd_type_for_runtime (type) 159590075Sobrien tree type; 159690075Sobrien{ 159790075Sobrien tree *slot; 159850397Sobrien 159990075Sobrien slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type, 160090075Sobrien TYPE_HASH (type), INSERT); 160190075Sobrien if (*slot == NULL) 160290075Sobrien { 160390075Sobrien tree runtime = (*lang_eh_runtime_type) (type); 160490075Sobrien *slot = tree_cons (type, runtime, NULL_TREE); 160590075Sobrien } 160690075Sobrien} 160750397Sobrien 160890075Sobrienstatic tree 160990075Sobrienlookup_type_for_runtime (type) 161090075Sobrien tree type; 161190075Sobrien{ 161290075Sobrien tree *slot; 161350397Sobrien 161490075Sobrien slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type, 161590075Sobrien TYPE_HASH (type), NO_INSERT); 161650397Sobrien 161790075Sobrien /* We should have always inserted the data earlier. */ 161890075Sobrien return TREE_VALUE (*slot); 161990075Sobrien} 162050397Sobrien 162190075Sobrien 162290075Sobrien/* Represent an entry in @TTypes for either catch actions 162390075Sobrien or exception filter actions. */ 162490075Sobrienstruct ttypes_filter 162590075Sobrien{ 162690075Sobrien tree t; 162790075Sobrien int filter; 162890075Sobrien}; 162950397Sobrien 163090075Sobrien/* Compare ENTRY (a ttypes_filter entry in the hash table) with DATA 163190075Sobrien (a tree) for a @TTypes type node we are thinking about adding. */ 163250397Sobrien 163390075Sobrienstatic int 163490075Sobrienttypes_filter_eq (pentry, pdata) 163590075Sobrien const PTR pentry; 163690075Sobrien const PTR pdata; 163790075Sobrien{ 163890075Sobrien const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry; 163990075Sobrien tree data = (tree) pdata; 164050397Sobrien 164190075Sobrien return entry->t == data; 164250397Sobrien} 164350397Sobrien 164490075Sobrienstatic hashval_t 164590075Sobrienttypes_filter_hash (pentry) 164690075Sobrien const PTR pentry; 164790075Sobrien{ 164890075Sobrien const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry; 164990075Sobrien return TYPE_HASH (entry->t); 165090075Sobrien} 165150397Sobrien 165290075Sobrien/* Compare ENTRY with DATA (both struct ttypes_filter) for a @TTypes 165390075Sobrien exception specification list we are thinking about adding. */ 165490075Sobrien/* ??? Currently we use the type lists in the order given. Someone 165590075Sobrien should put these in some canonical order. */ 165650397Sobrien 165790075Sobrienstatic int 165890075Sobrienehspec_filter_eq (pentry, pdata) 165990075Sobrien const PTR pentry; 166090075Sobrien const PTR pdata; 166150397Sobrien{ 166290075Sobrien const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry; 166390075Sobrien const struct ttypes_filter *data = (const struct ttypes_filter *) pdata; 166450397Sobrien 166590075Sobrien return type_list_equal (entry->t, data->t); 166690075Sobrien} 166750397Sobrien 166890075Sobrien/* Hash function for exception specification lists. */ 166950397Sobrien 167090075Sobrienstatic hashval_t 167190075Sobrienehspec_filter_hash (pentry) 167290075Sobrien const PTR pentry; 167390075Sobrien{ 167490075Sobrien const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry; 167590075Sobrien hashval_t h = 0; 167690075Sobrien tree list; 167750397Sobrien 167890075Sobrien for (list = entry->t; list ; list = TREE_CHAIN (list)) 167990075Sobrien h = (h << 5) + (h >> 27) + TYPE_HASH (TREE_VALUE (list)); 168090075Sobrien return h; 168150397Sobrien} 168250397Sobrien 168390075Sobrien/* Add TYPE to cfun->eh->ttype_data, using TYPES_HASH to speed 168490075Sobrien up the search. Return the filter value to be used. */ 168550397Sobrien 168690075Sobrienstatic int 168790075Sobrienadd_ttypes_entry (ttypes_hash, type) 168890075Sobrien htab_t ttypes_hash; 168990075Sobrien tree type; 169050397Sobrien{ 169190075Sobrien struct ttypes_filter **slot, *n; 169250397Sobrien 169390075Sobrien slot = (struct ttypes_filter **) 169490075Sobrien htab_find_slot_with_hash (ttypes_hash, type, TYPE_HASH (type), INSERT); 169550397Sobrien 169690075Sobrien if ((n = *slot) == NULL) 169750397Sobrien { 169890075Sobrien /* Filter value is a 1 based table index. */ 169950397Sobrien 170090075Sobrien n = (struct ttypes_filter *) xmalloc (sizeof (*n)); 170190075Sobrien n->t = type; 170290075Sobrien n->filter = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) + 1; 170390075Sobrien *slot = n; 170450397Sobrien 170590075Sobrien VARRAY_PUSH_TREE (cfun->eh->ttype_data, type); 170650397Sobrien } 170750397Sobrien 170890075Sobrien return n->filter; 170950397Sobrien} 171050397Sobrien 171190075Sobrien/* Add LIST to cfun->eh->ehspec_data, using EHSPEC_HASH and TYPES_HASH 171290075Sobrien to speed up the search. Return the filter value to be used. */ 171350397Sobrien 171490075Sobrienstatic int 171590075Sobrienadd_ehspec_entry (ehspec_hash, ttypes_hash, list) 171690075Sobrien htab_t ehspec_hash; 171790075Sobrien htab_t ttypes_hash; 171890075Sobrien tree list; 171950397Sobrien{ 172090075Sobrien struct ttypes_filter **slot, *n; 172190075Sobrien struct ttypes_filter dummy; 172250397Sobrien 172390075Sobrien dummy.t = list; 172490075Sobrien slot = (struct ttypes_filter **) 172590075Sobrien htab_find_slot (ehspec_hash, &dummy, INSERT); 172650397Sobrien 172790075Sobrien if ((n = *slot) == NULL) 172890075Sobrien { 172990075Sobrien /* Filter value is a -1 based byte index into a uleb128 buffer. */ 173050397Sobrien 173190075Sobrien n = (struct ttypes_filter *) xmalloc (sizeof (*n)); 173290075Sobrien n->t = list; 173390075Sobrien n->filter = -(VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) + 1); 173490075Sobrien *slot = n; 173550397Sobrien 173690075Sobrien /* Look up each type in the list and encode its filter 173790075Sobrien value as a uleb128. Terminate the list with 0. */ 173890075Sobrien for (; list ; list = TREE_CHAIN (list)) 173990075Sobrien push_uleb128 (&cfun->eh->ehspec_data, 174090075Sobrien add_ttypes_entry (ttypes_hash, TREE_VALUE (list))); 174190075Sobrien VARRAY_PUSH_UCHAR (cfun->eh->ehspec_data, 0); 174290075Sobrien } 174390075Sobrien 174490075Sobrien return n->filter; 174590075Sobrien} 174690075Sobrien 174790075Sobrien/* Generate the action filter values to be used for CATCH and 174890075Sobrien ALLOWED_EXCEPTIONS regions. When using dwarf2 exception regions, 174990075Sobrien we use lots of landing pads, and so every type or list can share 175090075Sobrien the same filter value, which saves table space. */ 175190075Sobrien 175290075Sobrienstatic void 175390075Sobrienassign_filter_values () 175450397Sobrien{ 175590075Sobrien int i; 175690075Sobrien htab_t ttypes, ehspec; 175750397Sobrien 175890075Sobrien VARRAY_TREE_INIT (cfun->eh->ttype_data, 16, "ttype_data"); 175990075Sobrien VARRAY_UCHAR_INIT (cfun->eh->ehspec_data, 64, "ehspec_data"); 176050397Sobrien 176190075Sobrien ttypes = htab_create (31, ttypes_filter_hash, ttypes_filter_eq, free); 176290075Sobrien ehspec = htab_create (31, ehspec_filter_hash, ehspec_filter_eq, free); 176350397Sobrien 176490075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 176550397Sobrien { 176690075Sobrien struct eh_region *r = cfun->eh->region_array[i]; 176750397Sobrien 176890075Sobrien /* Mind we don't process a region more than once. */ 176990075Sobrien if (!r || r->region_number != i) 177090075Sobrien continue; 177150397Sobrien 177290075Sobrien switch (r->type) 177390075Sobrien { 177490075Sobrien case ERT_CATCH: 177590075Sobrien /* Whatever type_list is (NULL or true list), we build a list 177690075Sobrien of filters for the region. */ 177790075Sobrien r->u.catch.filter_list = NULL_TREE; 177850397Sobrien 177990075Sobrien if (r->u.catch.type_list != NULL) 178090075Sobrien { 178190075Sobrien /* Get a filter value for each of the types caught and store 178290075Sobrien them in the region's dedicated list. */ 178390075Sobrien tree tp_node = r->u.catch.type_list; 178450397Sobrien 178590075Sobrien for (;tp_node; tp_node = TREE_CHAIN (tp_node)) 178690075Sobrien { 178790075Sobrien int flt = add_ttypes_entry (ttypes, TREE_VALUE (tp_node)); 178890075Sobrien tree flt_node = build_int_2 (flt, 0); 178950397Sobrien 179090075Sobrien r->u.catch.filter_list 179190075Sobrien = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list); 179290075Sobrien } 179390075Sobrien } 179490075Sobrien else 179590075Sobrien { 179690075Sobrien /* Get a filter value for the NULL list also since it will need 179790075Sobrien an action record anyway. */ 179890075Sobrien int flt = add_ttypes_entry (ttypes, NULL); 179990075Sobrien tree flt_node = build_int_2 (flt, 0); 180050397Sobrien 180190075Sobrien r->u.catch.filter_list 180290075Sobrien = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list); 180390075Sobrien } 180450397Sobrien 180590075Sobrien break; 180650397Sobrien 180790075Sobrien case ERT_ALLOWED_EXCEPTIONS: 180890075Sobrien r->u.allowed.filter 180990075Sobrien = add_ehspec_entry (ehspec, ttypes, r->u.allowed.type_list); 181090075Sobrien break; 181150397Sobrien 181290075Sobrien default: 181390075Sobrien break; 181490075Sobrien } 181550397Sobrien } 181690075Sobrien 181790075Sobrien htab_delete (ttypes); 181890075Sobrien htab_delete (ehspec); 181950397Sobrien} 182050397Sobrien 182190075Sobrienstatic void 182290075Sobrienbuild_post_landing_pads () 182350397Sobrien{ 182490075Sobrien int i; 182550397Sobrien 182690075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 182790075Sobrien { 182890075Sobrien struct eh_region *region = cfun->eh->region_array[i]; 182990075Sobrien rtx seq; 183050397Sobrien 183190075Sobrien /* Mind we don't process a region more than once. */ 183290075Sobrien if (!region || region->region_number != i) 183390075Sobrien continue; 183450397Sobrien 183590075Sobrien switch (region->type) 183690075Sobrien { 183790075Sobrien case ERT_TRY: 183890075Sobrien /* ??? Collect the set of all non-overlapping catch handlers 183990075Sobrien all the way up the chain until blocked by a cleanup. */ 184090075Sobrien /* ??? Outer try regions can share landing pads with inner 184190075Sobrien try regions if the types are completely non-overlapping, 184290075Sobrien and there are no intervening cleanups. */ 184350397Sobrien 184490075Sobrien region->post_landing_pad = gen_label_rtx (); 184550397Sobrien 184690075Sobrien start_sequence (); 184750397Sobrien 184890075Sobrien emit_label (region->post_landing_pad); 184950397Sobrien 185090075Sobrien /* ??? It is mighty inconvenient to call back into the 185190075Sobrien switch statement generation code in expand_end_case. 185290075Sobrien Rapid prototyping sez a sequence of ifs. */ 185390075Sobrien { 185490075Sobrien struct eh_region *c; 185590075Sobrien for (c = region->u.try.catch; c ; c = c->u.catch.next_catch) 185690075Sobrien { 185790075Sobrien /* ??? _Unwind_ForcedUnwind wants no match here. */ 185890075Sobrien if (c->u.catch.type_list == NULL) 185990075Sobrien emit_jump (c->label); 186090075Sobrien else 186190075Sobrien { 186290075Sobrien /* Need for one cmp/jump per type caught. Each type 186390075Sobrien list entry has a matching entry in the filter list 186490075Sobrien (see assign_filter_values). */ 186590075Sobrien tree tp_node = c->u.catch.type_list; 186690075Sobrien tree flt_node = c->u.catch.filter_list; 186750397Sobrien 186890075Sobrien for (; tp_node; ) 186990075Sobrien { 187090075Sobrien emit_cmp_and_jump_insns 187190075Sobrien (cfun->eh->filter, 187290075Sobrien GEN_INT (tree_low_cst (TREE_VALUE (flt_node), 0)), 187390075Sobrien EQ, NULL_RTX, word_mode, 0, c->label); 187450397Sobrien 187590075Sobrien tp_node = TREE_CHAIN (tp_node); 187690075Sobrien flt_node = TREE_CHAIN (flt_node); 187790075Sobrien } 187890075Sobrien } 187990075Sobrien } 188090075Sobrien } 188150397Sobrien 188290075Sobrien /* We delay the generation of the _Unwind_Resume until we generate 188390075Sobrien landing pads. We emit a marker here so as to get good control 188490075Sobrien flow data in the meantime. */ 188590075Sobrien region->resume 188690075Sobrien = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number)); 188790075Sobrien emit_barrier (); 188850397Sobrien 188990075Sobrien seq = get_insns (); 189090075Sobrien end_sequence (); 189150397Sobrien 189290075Sobrien emit_insns_before (seq, region->u.try.catch->label); 189390075Sobrien break; 189450397Sobrien 189590075Sobrien case ERT_ALLOWED_EXCEPTIONS: 189690075Sobrien region->post_landing_pad = gen_label_rtx (); 189750397Sobrien 189890075Sobrien start_sequence (); 189950397Sobrien 190090075Sobrien emit_label (region->post_landing_pad); 190150397Sobrien 190290075Sobrien emit_cmp_and_jump_insns (cfun->eh->filter, 190390075Sobrien GEN_INT (region->u.allowed.filter), 190490075Sobrien EQ, NULL_RTX, word_mode, 0, region->label); 190550397Sobrien 190690075Sobrien /* We delay the generation of the _Unwind_Resume until we generate 190790075Sobrien landing pads. We emit a marker here so as to get good control 190890075Sobrien flow data in the meantime. */ 190990075Sobrien region->resume 191090075Sobrien = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number)); 191190075Sobrien emit_barrier (); 191250397Sobrien 191390075Sobrien seq = get_insns (); 191490075Sobrien end_sequence (); 191590075Sobrien 191690075Sobrien emit_insns_before (seq, region->label); 191790075Sobrien break; 191890075Sobrien 191990075Sobrien case ERT_CLEANUP: 192090075Sobrien case ERT_MUST_NOT_THROW: 192190075Sobrien region->post_landing_pad = region->label; 192290075Sobrien break; 192390075Sobrien 192490075Sobrien case ERT_CATCH: 192590075Sobrien case ERT_THROW: 192690075Sobrien /* Nothing to do. */ 192790075Sobrien break; 192890075Sobrien 192990075Sobrien default: 193090075Sobrien abort (); 193190075Sobrien } 193290075Sobrien } 193350397Sobrien} 193450397Sobrien 193590075Sobrien/* Replace RESX patterns with jumps to the next handler if any, or calls to 193690075Sobrien _Unwind_Resume otherwise. */ 193750397Sobrien 193890075Sobrienstatic void 193990075Sobrienconnect_post_landing_pads () 194050397Sobrien{ 194190075Sobrien int i; 194250397Sobrien 194390075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 194450397Sobrien { 194590075Sobrien struct eh_region *region = cfun->eh->region_array[i]; 194690075Sobrien struct eh_region *outer; 194790075Sobrien rtx seq; 194850397Sobrien 194990075Sobrien /* Mind we don't process a region more than once. */ 195090075Sobrien if (!region || region->region_number != i) 195190075Sobrien continue; 195250397Sobrien 195390075Sobrien /* If there is no RESX, or it has been deleted by flow, there's 195490075Sobrien nothing to fix up. */ 195590075Sobrien if (! region->resume || INSN_DELETED_P (region->resume)) 195690075Sobrien continue; 195750397Sobrien 195890075Sobrien /* Search for another landing pad in this function. */ 195990075Sobrien for (outer = region->outer; outer ; outer = outer->outer) 196090075Sobrien if (outer->post_landing_pad) 196190075Sobrien break; 196250397Sobrien 196390075Sobrien start_sequence (); 196450397Sobrien 196590075Sobrien if (outer) 196690075Sobrien emit_jump (outer->post_landing_pad); 196790075Sobrien else 196890075Sobrien emit_library_call (unwind_resume_libfunc, LCT_THROW, 196990075Sobrien VOIDmode, 1, cfun->eh->exc_ptr, Pmode); 197050397Sobrien 197190075Sobrien seq = get_insns (); 197290075Sobrien end_sequence (); 197390075Sobrien emit_insns_before (seq, region->resume); 197490075Sobrien delete_insn (region->resume); 197550397Sobrien } 197650397Sobrien} 197750397Sobrien 197890075Sobrien 197990075Sobrienstatic void 198090075Sobriendw2_build_landing_pads () 198150397Sobrien{ 198290075Sobrien int i; 198390075Sobrien unsigned int j; 198450397Sobrien 198590075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 198690075Sobrien { 198790075Sobrien struct eh_region *region = cfun->eh->region_array[i]; 198890075Sobrien rtx seq; 198990075Sobrien bool clobbers_hard_regs = false; 199050397Sobrien 199190075Sobrien /* Mind we don't process a region more than once. */ 199290075Sobrien if (!region || region->region_number != i) 199390075Sobrien continue; 199450397Sobrien 199590075Sobrien if (region->type != ERT_CLEANUP 199690075Sobrien && region->type != ERT_TRY 199790075Sobrien && region->type != ERT_ALLOWED_EXCEPTIONS) 199890075Sobrien continue; 199950397Sobrien 200090075Sobrien start_sequence (); 200150397Sobrien 200290075Sobrien region->landing_pad = gen_label_rtx (); 200390075Sobrien emit_label (region->landing_pad); 200450397Sobrien 200590075Sobrien#ifdef HAVE_exception_receiver 200690075Sobrien if (HAVE_exception_receiver) 200790075Sobrien emit_insn (gen_exception_receiver ()); 200890075Sobrien else 200990075Sobrien#endif 201090075Sobrien#ifdef HAVE_nonlocal_goto_receiver 201190075Sobrien if (HAVE_nonlocal_goto_receiver) 201290075Sobrien emit_insn (gen_nonlocal_goto_receiver ()); 201390075Sobrien else 201490075Sobrien#endif 201590075Sobrien { /* Nothing */ } 201650397Sobrien 201790075Sobrien /* If the eh_return data registers are call-saved, then we 201890075Sobrien won't have considered them clobbered from the call that 201990075Sobrien threw. Kill them now. */ 202090075Sobrien for (j = 0; ; ++j) 202190075Sobrien { 202290075Sobrien unsigned r = EH_RETURN_DATA_REGNO (j); 202390075Sobrien if (r == INVALID_REGNUM) 202490075Sobrien break; 202590075Sobrien if (! call_used_regs[r]) 202690075Sobrien { 202790075Sobrien emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, r))); 202890075Sobrien clobbers_hard_regs = true; 202990075Sobrien } 203090075Sobrien } 203152284Sobrien 203290075Sobrien if (clobbers_hard_regs) 203390075Sobrien { 203490075Sobrien /* @@@ This is a kludge. Not all machine descriptions define a 203590075Sobrien blockage insn, but we must not allow the code we just generated 203690075Sobrien to be reordered by scheduling. So emit an ASM_INPUT to act as 203790075Sobrien blockage insn. */ 203890075Sobrien emit_insn (gen_rtx_ASM_INPUT (VOIDmode, "")); 203990075Sobrien } 204052284Sobrien 204190075Sobrien emit_move_insn (cfun->eh->exc_ptr, 204290075Sobrien gen_rtx_REG (Pmode, EH_RETURN_DATA_REGNO (0))); 204390075Sobrien emit_move_insn (cfun->eh->filter, 204490075Sobrien gen_rtx_REG (word_mode, EH_RETURN_DATA_REGNO (1))); 204552284Sobrien 204690075Sobrien seq = get_insns (); 204790075Sobrien end_sequence (); 204852284Sobrien 204990075Sobrien emit_insns_before (seq, region->post_landing_pad); 205052284Sobrien } 205150397Sobrien} 205250397Sobrien 205390075Sobrien 205490075Sobrienstruct sjlj_lp_info 205590075Sobrien{ 205690075Sobrien int directly_reachable; 205790075Sobrien int action_index; 205890075Sobrien int dispatch_index; 205990075Sobrien int call_site_index; 206090075Sobrien}; 206152284Sobrien 206290075Sobrienstatic bool 206390075Sobriensjlj_find_directly_reachable_regions (lp_info) 206490075Sobrien struct sjlj_lp_info *lp_info; 206552284Sobrien{ 206690075Sobrien rtx insn; 206790075Sobrien bool found_one = false; 206852284Sobrien 206990075Sobrien for (insn = get_insns (); insn ; insn = NEXT_INSN (insn)) 207052284Sobrien { 207190075Sobrien struct eh_region *region; 207290075Sobrien enum reachable_code rc; 207390075Sobrien tree type_thrown; 207490075Sobrien rtx note; 207590075Sobrien 207690075Sobrien if (! INSN_P (insn)) 207790075Sobrien continue; 207890075Sobrien 207990075Sobrien note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 208090075Sobrien if (!note || INTVAL (XEXP (note, 0)) <= 0) 208190075Sobrien continue; 208290075Sobrien 208390075Sobrien region = cfun->eh->region_array[INTVAL (XEXP (note, 0))]; 208490075Sobrien 208590075Sobrien type_thrown = NULL_TREE; 208690075Sobrien if (region->type == ERT_THROW) 208790075Sobrien { 208890075Sobrien type_thrown = region->u.throw.type; 208990075Sobrien region = region->outer; 209090075Sobrien } 209190075Sobrien 209290075Sobrien /* Find the first containing region that might handle the exception. 209390075Sobrien That's the landing pad to which we will transfer control. */ 209490075Sobrien rc = RNL_NOT_CAUGHT; 209590075Sobrien for (; region; region = region->outer) 209690075Sobrien { 209790075Sobrien rc = reachable_next_level (region, type_thrown, 0); 209890075Sobrien if (rc != RNL_NOT_CAUGHT) 209990075Sobrien break; 210090075Sobrien } 210190075Sobrien if (rc == RNL_MAYBE_CAUGHT || rc == RNL_CAUGHT) 210290075Sobrien { 210390075Sobrien lp_info[region->region_number].directly_reachable = 1; 210490075Sobrien found_one = true; 210590075Sobrien } 210652284Sobrien } 210752284Sobrien 210890075Sobrien return found_one; 210952284Sobrien} 211052284Sobrien 211190075Sobrienstatic void 211290075Sobriensjlj_assign_call_site_values (dispatch_label, lp_info) 211390075Sobrien rtx dispatch_label; 211490075Sobrien struct sjlj_lp_info *lp_info; 211590075Sobrien{ 211690075Sobrien htab_t ar_hash; 211790075Sobrien int i, index; 211850397Sobrien 211990075Sobrien /* First task: build the action table. */ 212050397Sobrien 212190075Sobrien VARRAY_UCHAR_INIT (cfun->eh->action_record_data, 64, "action_record_data"); 212290075Sobrien ar_hash = htab_create (31, action_record_hash, action_record_eq, free); 212350397Sobrien 212490075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 212590075Sobrien if (lp_info[i].directly_reachable) 212690075Sobrien { 212790075Sobrien struct eh_region *r = cfun->eh->region_array[i]; 212890075Sobrien r->landing_pad = dispatch_label; 212990075Sobrien lp_info[i].action_index = collect_one_action_chain (ar_hash, r); 213090075Sobrien if (lp_info[i].action_index != -1) 213190075Sobrien cfun->uses_eh_lsda = 1; 213290075Sobrien } 213350397Sobrien 213490075Sobrien htab_delete (ar_hash); 213550397Sobrien 213690075Sobrien /* Next: assign dispatch values. In dwarf2 terms, this would be the 213790075Sobrien landing pad label for the region. For sjlj though, there is one 213890075Sobrien common landing pad from which we dispatch to the post-landing pads. 213950397Sobrien 214090075Sobrien A region receives a dispatch index if it is directly reachable 214190075Sobrien and requires in-function processing. Regions that share post-landing 214290075Sobrien pads may share dispatch indices. */ 214390075Sobrien /* ??? Post-landing pad sharing doesn't actually happen at the moment 214490075Sobrien (see build_post_landing_pads) so we don't bother checking for it. */ 214550397Sobrien 214690075Sobrien index = 0; 214790075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 214890075Sobrien if (lp_info[i].directly_reachable) 214990075Sobrien lp_info[i].dispatch_index = index++; 215050397Sobrien 215190075Sobrien /* Finally: assign call-site values. If dwarf2 terms, this would be 215290075Sobrien the region number assigned by convert_to_eh_region_ranges, but 215390075Sobrien handles no-action and must-not-throw differently. */ 215450397Sobrien 215590075Sobrien call_site_base = 1; 215690075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 215790075Sobrien if (lp_info[i].directly_reachable) 215890075Sobrien { 215990075Sobrien int action = lp_info[i].action_index; 216090075Sobrien 216190075Sobrien /* Map must-not-throw to otherwise unused call-site index 0. */ 216290075Sobrien if (action == -2) 216390075Sobrien index = 0; 216490075Sobrien /* Map no-action to otherwise unused call-site index -1. */ 216590075Sobrien else if (action == -1) 216690075Sobrien index = -1; 216790075Sobrien /* Otherwise, look it up in the table. */ 216890075Sobrien else 216990075Sobrien index = add_call_site (GEN_INT (lp_info[i].dispatch_index), action); 217090075Sobrien 217190075Sobrien lp_info[i].call_site_index = index; 217290075Sobrien } 217390075Sobrien} 217490075Sobrien 217590075Sobrienstatic void 217690075Sobriensjlj_mark_call_sites (lp_info) 217790075Sobrien struct sjlj_lp_info *lp_info; 217890075Sobrien{ 217990075Sobrien int last_call_site = -2; 218090075Sobrien rtx insn, mem; 218190075Sobrien 218290075Sobrien for (insn = get_insns (); insn ; insn = NEXT_INSN (insn)) 218350397Sobrien { 218490075Sobrien struct eh_region *region; 218590075Sobrien int this_call_site; 218690075Sobrien rtx note, before, p; 218750397Sobrien 218890075Sobrien /* Reset value tracking at extended basic block boundaries. */ 218990075Sobrien if (GET_CODE (insn) == CODE_LABEL) 219090075Sobrien last_call_site = -2; 219150397Sobrien 219290075Sobrien if (! INSN_P (insn)) 219390075Sobrien continue; 219450397Sobrien 219590075Sobrien note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 219690075Sobrien if (!note) 219790075Sobrien { 219890075Sobrien /* Calls (and trapping insns) without notes are outside any 219990075Sobrien exception handling region in this function. Mark them as 220090075Sobrien no action. */ 220190075Sobrien if (GET_CODE (insn) == CALL_INSN 220290075Sobrien || (flag_non_call_exceptions 220390075Sobrien && may_trap_p (PATTERN (insn)))) 220490075Sobrien this_call_site = -1; 220590075Sobrien else 220690075Sobrien continue; 220790075Sobrien } 220890075Sobrien else 220990075Sobrien { 221090075Sobrien /* Calls that are known to not throw need not be marked. */ 221190075Sobrien if (INTVAL (XEXP (note, 0)) <= 0) 221290075Sobrien continue; 221350397Sobrien 221490075Sobrien region = cfun->eh->region_array[INTVAL (XEXP (note, 0))]; 221590075Sobrien this_call_site = lp_info[region->region_number].call_site_index; 221690075Sobrien } 221750397Sobrien 221890075Sobrien if (this_call_site == last_call_site) 221990075Sobrien continue; 222050397Sobrien 222190075Sobrien /* Don't separate a call from it's argument loads. */ 222290075Sobrien before = insn; 222390075Sobrien if (GET_CODE (insn) == CALL_INSN) 222490075Sobrien before = find_first_parameter_load (insn, NULL_RTX); 222550397Sobrien 222690075Sobrien start_sequence (); 222790075Sobrien mem = adjust_address (cfun->eh->sjlj_fc, TYPE_MODE (integer_type_node), 222890075Sobrien sjlj_fc_call_site_ofs); 222990075Sobrien emit_move_insn (mem, GEN_INT (this_call_site)); 223090075Sobrien p = get_insns (); 223190075Sobrien end_sequence (); 223250397Sobrien 223390075Sobrien emit_insns_before (p, before); 223490075Sobrien last_call_site = this_call_site; 223550397Sobrien } 223650397Sobrien} 223750397Sobrien 223890075Sobrien/* Construct the SjLj_Function_Context. */ 223950397Sobrien 224090075Sobrienstatic void 224190075Sobriensjlj_emit_function_enter (dispatch_label) 224290075Sobrien rtx dispatch_label; 224350397Sobrien{ 224490075Sobrien rtx fn_begin, fc, mem, seq; 224550397Sobrien 224690075Sobrien fc = cfun->eh->sjlj_fc; 224750397Sobrien 224890075Sobrien start_sequence (); 224950397Sobrien 225090075Sobrien /* We're storing this libcall's address into memory instead of 225190075Sobrien calling it directly. Thus, we must call assemble_external_libcall 225290075Sobrien here, as we can not depend on emit_library_call to do it for us. */ 225390075Sobrien assemble_external_libcall (eh_personality_libfunc); 225490075Sobrien mem = adjust_address (fc, Pmode, sjlj_fc_personality_ofs); 225590075Sobrien emit_move_insn (mem, eh_personality_libfunc); 225690075Sobrien 225790075Sobrien mem = adjust_address (fc, Pmode, sjlj_fc_lsda_ofs); 225890075Sobrien if (cfun->uses_eh_lsda) 225950397Sobrien { 226090075Sobrien char buf[20]; 226190075Sobrien ASM_GENERATE_INTERNAL_LABEL (buf, "LLSDA", sjlj_funcdef_number); 226290075Sobrien emit_move_insn (mem, gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf))); 226350397Sobrien } 226490075Sobrien else 226590075Sobrien emit_move_insn (mem, const0_rtx); 226650397Sobrien 226790075Sobrien#ifdef DONT_USE_BUILTIN_SETJMP 226890075Sobrien { 226990075Sobrien rtx x, note; 227090075Sobrien x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_RETURNS_TWICE, 227190075Sobrien TYPE_MODE (integer_type_node), 1, 227290075Sobrien plus_constant (XEXP (fc, 0), 227390075Sobrien sjlj_fc_jbuf_ofs), Pmode); 227450397Sobrien 227590075Sobrien note = emit_note (NULL, NOTE_INSN_EXPECTED_VALUE); 227690075Sobrien NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, x, const0_rtx); 227750397Sobrien 227890075Sobrien emit_cmp_and_jump_insns (x, const0_rtx, NE, 0, 227990075Sobrien TYPE_MODE (integer_type_node), 0, dispatch_label); 228090075Sobrien } 228190075Sobrien#else 228290075Sobrien expand_builtin_setjmp_setup (plus_constant (XEXP (fc, 0), sjlj_fc_jbuf_ofs), 228390075Sobrien dispatch_label); 228490075Sobrien#endif 228550397Sobrien 228690075Sobrien emit_library_call (unwind_sjlj_register_libfunc, LCT_NORMAL, VOIDmode, 228790075Sobrien 1, XEXP (fc, 0), Pmode); 228890075Sobrien 228990075Sobrien seq = get_insns (); 229050397Sobrien end_sequence (); 229150397Sobrien 229290075Sobrien /* ??? Instead of doing this at the beginning of the function, 229390075Sobrien do this in a block that is at loop level 0 and dominates all 229490075Sobrien can_throw_internal instructions. */ 229550397Sobrien 229690075Sobrien for (fn_begin = get_insns (); ; fn_begin = NEXT_INSN (fn_begin)) 229790075Sobrien if (GET_CODE (fn_begin) == NOTE 229890075Sobrien && NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG) 229990075Sobrien break; 230090075Sobrien emit_insns_after (seq, fn_begin); 230150397Sobrien} 230250397Sobrien 230390075Sobrien/* Call back from expand_function_end to know where we should put 230490075Sobrien the call to unwind_sjlj_unregister_libfunc if needed. */ 230550397Sobrien 230650397Sobrienvoid 230790075Sobriensjlj_emit_function_exit_after (after) 230890075Sobrien rtx after; 230950397Sobrien{ 231090075Sobrien cfun->eh->sjlj_exit_after = after; 231150397Sobrien} 231250397Sobrien 231390075Sobrienstatic void 231490075Sobriensjlj_emit_function_exit () 231550397Sobrien{ 231690075Sobrien rtx seq; 231750397Sobrien 231890075Sobrien start_sequence (); 231950397Sobrien 232090075Sobrien emit_library_call (unwind_sjlj_unregister_libfunc, LCT_NORMAL, VOIDmode, 232190075Sobrien 1, XEXP (cfun->eh->sjlj_fc, 0), Pmode); 232250397Sobrien 232390075Sobrien seq = get_insns (); 232490075Sobrien end_sequence (); 232550397Sobrien 232690075Sobrien /* ??? Really this can be done in any block at loop level 0 that 232790075Sobrien post-dominates all can_throw_internal instructions. This is 232890075Sobrien the last possible moment. */ 232950397Sobrien 233090075Sobrien emit_insns_after (seq, cfun->eh->sjlj_exit_after); 233190075Sobrien} 233250397Sobrien 233390075Sobrienstatic void 233490075Sobriensjlj_emit_dispatch_table (dispatch_label, lp_info) 233590075Sobrien rtx dispatch_label; 233690075Sobrien struct sjlj_lp_info *lp_info; 233790075Sobrien{ 233890075Sobrien int i, first_reachable; 233990075Sobrien rtx mem, dispatch, seq, fc; 234050397Sobrien 234190075Sobrien fc = cfun->eh->sjlj_fc; 234250397Sobrien 234390075Sobrien start_sequence (); 234450397Sobrien 234590075Sobrien emit_label (dispatch_label); 234650397Sobrien 234790075Sobrien#ifndef DONT_USE_BUILTIN_SETJMP 234890075Sobrien expand_builtin_setjmp_receiver (dispatch_label); 234990075Sobrien#endif 235050397Sobrien 235190075Sobrien /* Load up dispatch index, exc_ptr and filter values from the 235290075Sobrien function context. */ 235390075Sobrien mem = adjust_address (fc, TYPE_MODE (integer_type_node), 235490075Sobrien sjlj_fc_call_site_ofs); 235590075Sobrien dispatch = copy_to_reg (mem); 235650397Sobrien 235790075Sobrien mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs); 235890075Sobrien if (word_mode != Pmode) 235950397Sobrien { 236090075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED 236190075Sobrien mem = convert_memory_address (Pmode, mem); 236290075Sobrien#else 236390075Sobrien mem = convert_to_mode (Pmode, mem, 0); 236490075Sobrien#endif 236590075Sobrien } 236690075Sobrien emit_move_insn (cfun->eh->exc_ptr, mem); 236750397Sobrien 236890075Sobrien mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs + UNITS_PER_WORD); 236990075Sobrien emit_move_insn (cfun->eh->filter, mem); 237050397Sobrien 237190075Sobrien /* Jump to one of the directly reachable regions. */ 237290075Sobrien /* ??? This really ought to be using a switch statement. */ 237390075Sobrien 237490075Sobrien first_reachable = 0; 237590075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 237690075Sobrien { 237790075Sobrien if (! lp_info[i].directly_reachable) 237890075Sobrien continue; 237990075Sobrien 238090075Sobrien if (! first_reachable) 238150397Sobrien { 238290075Sobrien first_reachable = i; 238390075Sobrien continue; 238450397Sobrien } 238590075Sobrien 238690075Sobrien emit_cmp_and_jump_insns (dispatch, GEN_INT (lp_info[i].dispatch_index), 238790075Sobrien EQ, NULL_RTX, TYPE_MODE (integer_type_node), 0, 238890075Sobrien cfun->eh->region_array[i]->post_landing_pad); 238950397Sobrien } 239050397Sobrien 239190075Sobrien seq = get_insns (); 239290075Sobrien end_sequence (); 239350397Sobrien 239490075Sobrien emit_insns_before (seq, (cfun->eh->region_array[first_reachable] 239590075Sobrien ->post_landing_pad)); 239650397Sobrien} 239750397Sobrien 239850397Sobrienstatic void 239990075Sobriensjlj_build_landing_pads () 240050397Sobrien{ 240190075Sobrien struct sjlj_lp_info *lp_info; 240250397Sobrien 240390075Sobrien lp_info = (struct sjlj_lp_info *) xcalloc (cfun->eh->last_region_number + 1, 240490075Sobrien sizeof (struct sjlj_lp_info)); 240550397Sobrien 240690075Sobrien if (sjlj_find_directly_reachable_regions (lp_info)) 240750397Sobrien { 240890075Sobrien rtx dispatch_label = gen_label_rtx (); 240952284Sobrien 241090075Sobrien cfun->eh->sjlj_fc 241190075Sobrien = assign_stack_local (TYPE_MODE (sjlj_fc_type_node), 241290075Sobrien int_size_in_bytes (sjlj_fc_type_node), 241390075Sobrien TYPE_ALIGN (sjlj_fc_type_node)); 241450397Sobrien 241590075Sobrien sjlj_assign_call_site_values (dispatch_label, lp_info); 241690075Sobrien sjlj_mark_call_sites (lp_info); 241750397Sobrien 241890075Sobrien sjlj_emit_function_enter (dispatch_label); 241990075Sobrien sjlj_emit_dispatch_table (dispatch_label, lp_info); 242090075Sobrien sjlj_emit_function_exit (); 242150397Sobrien } 242250397Sobrien 242390075Sobrien free (lp_info); 242450397Sobrien} 242550397Sobrien 242652284Sobrienvoid 242790075Sobrienfinish_eh_generation () 242850397Sobrien{ 242990075Sobrien /* Nothing to do if no regions created. */ 243090075Sobrien if (cfun->eh->region_tree == NULL) 243190075Sobrien return; 243250397Sobrien 243390075Sobrien /* The object here is to provide find_basic_blocks with detailed 243490075Sobrien information (via reachable_handlers) on how exception control 243590075Sobrien flows within the function. In this first pass, we can include 243690075Sobrien type information garnered from ERT_THROW and ERT_ALLOWED_EXCEPTIONS 243790075Sobrien regions, and hope that it will be useful in deleting unreachable 243890075Sobrien handlers. Subsequently, we will generate landing pads which will 243990075Sobrien connect many of the handlers, and then type information will not 244090075Sobrien be effective. Still, this is a win over previous implementations. */ 244150397Sobrien 244290075Sobrien rebuild_jump_labels (get_insns ()); 244390075Sobrien find_basic_blocks (get_insns (), max_reg_num (), 0); 244490075Sobrien cleanup_cfg (CLEANUP_PRE_LOOP); 244550397Sobrien 244690075Sobrien /* These registers are used by the landing pads. Make sure they 244790075Sobrien have been generated. */ 244890075Sobrien get_exception_pointer (cfun); 244990075Sobrien get_exception_filter (cfun); 245050397Sobrien 245190075Sobrien /* Construct the landing pads. */ 245250397Sobrien 245390075Sobrien assign_filter_values (); 245490075Sobrien build_post_landing_pads (); 245590075Sobrien connect_post_landing_pads (); 245690075Sobrien if (USING_SJLJ_EXCEPTIONS) 245790075Sobrien sjlj_build_landing_pads (); 245890075Sobrien else 245990075Sobrien dw2_build_landing_pads (); 246050397Sobrien 246190075Sobrien cfun->eh->built_landing_pads = 1; 246250397Sobrien 246390075Sobrien /* We've totally changed the CFG. Start over. */ 246490075Sobrien find_exception_handler_labels (); 246590075Sobrien rebuild_jump_labels (get_insns ()); 246690075Sobrien find_basic_blocks (get_insns (), max_reg_num (), 0); 246790075Sobrien cleanup_cfg (CLEANUP_PRE_LOOP); 246890075Sobrien} 246990075Sobrien 247090075Sobrien/* This section handles removing dead code for flow. */ 247152284Sobrien 247290075Sobrien/* Remove LABEL from the exception_handler_labels list. */ 247350397Sobrien 247490075Sobrienstatic void 247590075Sobrienremove_exception_handler_label (label) 247690075Sobrien rtx label; 247790075Sobrien{ 247890075Sobrien rtx *pl, l; 247950397Sobrien 248090075Sobrien /* If exception_handler_labels was not built yet, 248190075Sobrien there is nothing to do. */ 248290075Sobrien if (exception_handler_labels == NULL) 248390075Sobrien return; 248450397Sobrien 248590075Sobrien for (pl = &exception_handler_labels, l = *pl; 248690075Sobrien XEXP (l, 0) != label; 248790075Sobrien pl = &XEXP (l, 1), l = *pl) 248890075Sobrien continue; 248950397Sobrien 249090075Sobrien *pl = XEXP (l, 1); 249190075Sobrien free_EXPR_LIST_node (l); 249250397Sobrien} 249350397Sobrien 249490075Sobrien/* Splice REGION from the region tree etc. */ 249550397Sobrien 249690075Sobrienstatic void 249790075Sobrienremove_eh_handler (region) 249890075Sobrien struct eh_region *region; 249950397Sobrien{ 250090075Sobrien struct eh_region **pp, *p; 250190075Sobrien rtx lab; 250290075Sobrien int i; 250350397Sobrien 250490075Sobrien /* For the benefit of efficiently handling REG_EH_REGION notes, 250590075Sobrien replace this region in the region array with its containing 250690075Sobrien region. Note that previous region deletions may result in 250790075Sobrien multiple copies of this region in the array, so we have to 250890075Sobrien search the whole thing. */ 250990075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 251090075Sobrien if (cfun->eh->region_array[i] == region) 251190075Sobrien cfun->eh->region_array[i] = region->outer; 251250397Sobrien 251390075Sobrien if (cfun->eh->built_landing_pads) 251490075Sobrien lab = region->landing_pad; 251590075Sobrien else 251690075Sobrien lab = region->label; 251790075Sobrien if (lab) 251890075Sobrien remove_exception_handler_label (lab); 251950397Sobrien 252090075Sobrien if (region->outer) 252190075Sobrien pp = ®ion->outer->inner; 252290075Sobrien else 252390075Sobrien pp = &cfun->eh->region_tree; 252490075Sobrien for (p = *pp; p != region; pp = &p->next_peer, p = *pp) 252590075Sobrien continue; 252650397Sobrien 252790075Sobrien if (region->inner) 252890075Sobrien { 252990075Sobrien for (p = region->inner; p->next_peer ; p = p->next_peer) 253090075Sobrien p->outer = region->outer; 253190075Sobrien p->next_peer = region->next_peer; 253290075Sobrien p->outer = region->outer; 253390075Sobrien *pp = region->inner; 253490075Sobrien } 253590075Sobrien else 253690075Sobrien *pp = region->next_peer; 253750397Sobrien 253890075Sobrien if (region->type == ERT_CATCH) 253990075Sobrien { 254090075Sobrien struct eh_region *try, *next, *prev; 254152284Sobrien 254290075Sobrien for (try = region->next_peer; 254390075Sobrien try->type == ERT_CATCH; 254490075Sobrien try = try->next_peer) 254590075Sobrien continue; 254690075Sobrien if (try->type != ERT_TRY) 254790075Sobrien abort (); 254890075Sobrien 254990075Sobrien next = region->u.catch.next_catch; 255090075Sobrien prev = region->u.catch.prev_catch; 255190075Sobrien 255290075Sobrien if (next) 255390075Sobrien next->u.catch.prev_catch = prev; 255490075Sobrien else 255590075Sobrien try->u.try.last_catch = prev; 255690075Sobrien if (prev) 255790075Sobrien prev->u.catch.next_catch = next; 255890075Sobrien else 255990075Sobrien { 256090075Sobrien try->u.try.catch = next; 256190075Sobrien if (! next) 256290075Sobrien remove_eh_handler (try); 256390075Sobrien } 256490075Sobrien } 256590075Sobrien 256690075Sobrien free (region); 256750397Sobrien} 256850397Sobrien 256990075Sobrien/* LABEL heads a basic block that is about to be deleted. If this 257090075Sobrien label corresponds to an exception region, we may be able to 257190075Sobrien delete the region. */ 257250397Sobrien 257350397Sobrienvoid 257490075Sobrienmaybe_remove_eh_handler (label) 257590075Sobrien rtx label; 257650397Sobrien{ 257790075Sobrien int i; 257850397Sobrien 257990075Sobrien /* ??? After generating landing pads, it's not so simple to determine 258090075Sobrien if the region data is completely unused. One must examine the 258190075Sobrien landing pad and the post landing pad, and whether an inner try block 258290075Sobrien is referencing the catch handlers directly. */ 258390075Sobrien if (cfun->eh->built_landing_pads) 258450397Sobrien return; 258550397Sobrien 258690075Sobrien for (i = cfun->eh->last_region_number; i > 0; --i) 258750397Sobrien { 258890075Sobrien struct eh_region *region = cfun->eh->region_array[i]; 258990075Sobrien if (region && region->label == label) 259050397Sobrien { 259190075Sobrien /* Flow will want to remove MUST_NOT_THROW regions as unreachable 259290075Sobrien because there is no path to the fallback call to terminate. 259390075Sobrien But the region continues to affect call-site data until there 259490075Sobrien are no more contained calls, which we don't see here. */ 259590075Sobrien if (region->type == ERT_MUST_NOT_THROW) 259690075Sobrien { 259790075Sobrien remove_exception_handler_label (region->label); 259890075Sobrien region->label = NULL_RTX; 259990075Sobrien } 260090075Sobrien else 260190075Sobrien remove_eh_handler (region); 260290075Sobrien break; 260350397Sobrien } 260450397Sobrien } 260550397Sobrien} 260650397Sobrien 260790075Sobrien 260890075Sobrien/* This section describes CFG exception edges for flow. */ 260950397Sobrien 261090075Sobrien/* For communicating between calls to reachable_next_level. */ 261190075Sobrienstruct reachable_info 261250397Sobrien{ 261390075Sobrien tree types_caught; 261490075Sobrien tree types_allowed; 261590075Sobrien rtx handlers; 261690075Sobrien}; 261790075Sobrien 261890075Sobrien/* A subroutine of reachable_next_level. Return true if TYPE, or a 261990075Sobrien base class of TYPE, is in HANDLED. */ 262090075Sobrien 262190075Sobrienstatic int 262290075Sobriencheck_handled (handled, type) 262390075Sobrien tree handled, type; 262490075Sobrien{ 262590075Sobrien tree t; 262690075Sobrien 262790075Sobrien /* We can check for exact matches without front-end help. */ 262890075Sobrien if (! lang_eh_type_covers) 262990075Sobrien { 263090075Sobrien for (t = handled; t ; t = TREE_CHAIN (t)) 263190075Sobrien if (TREE_VALUE (t) == type) 263290075Sobrien return 1; 263390075Sobrien } 263490075Sobrien else 263590075Sobrien { 263690075Sobrien for (t = handled; t ; t = TREE_CHAIN (t)) 263790075Sobrien if ((*lang_eh_type_covers) (TREE_VALUE (t), type)) 263890075Sobrien return 1; 263990075Sobrien } 264090075Sobrien 264150397Sobrien return 0; 264250397Sobrien} 264350397Sobrien 264490075Sobrien/* A subroutine of reachable_next_level. If we are collecting a list 264590075Sobrien of handlers, add one. After landing pad generation, reference 264690075Sobrien it instead of the handlers themselves. Further, the handlers are 264790075Sobrien all wired together, so by referencing one, we've got them all. 264890075Sobrien Before landing pad generation we reference each handler individually. 264950397Sobrien 265090075Sobrien LP_REGION contains the landing pad; REGION is the handler. */ 265150397Sobrien 265290075Sobrienstatic void 265390075Sobrienadd_reachable_handler (info, lp_region, region) 265490075Sobrien struct reachable_info *info; 265590075Sobrien struct eh_region *lp_region; 265690075Sobrien struct eh_region *region; 265750397Sobrien{ 265890075Sobrien if (! info) 265950397Sobrien return; 266050397Sobrien 266190075Sobrien if (cfun->eh->built_landing_pads) 266250397Sobrien { 266390075Sobrien if (! info->handlers) 266490075Sobrien info->handlers = alloc_INSN_LIST (lp_region->landing_pad, NULL_RTX); 266550397Sobrien } 266690075Sobrien else 266790075Sobrien info->handlers = alloc_INSN_LIST (region->label, info->handlers); 266850397Sobrien} 266950397Sobrien 267090075Sobrien/* Process one level of exception regions for reachability. 267190075Sobrien If TYPE_THROWN is non-null, then it is the *exact* type being 267290075Sobrien propagated. If INFO is non-null, then collect handler labels 267390075Sobrien and caught/allowed type information between invocations. */ 267450397Sobrien 267590075Sobrienstatic enum reachable_code 267690075Sobrienreachable_next_level (region, type_thrown, info) 267790075Sobrien struct eh_region *region; 267890075Sobrien tree type_thrown; 267990075Sobrien struct reachable_info *info; 268050397Sobrien{ 268190075Sobrien switch (region->type) 268290075Sobrien { 268390075Sobrien case ERT_CLEANUP: 268490075Sobrien /* Before landing-pad generation, we model control flow 268590075Sobrien directly to the individual handlers. In this way we can 268690075Sobrien see that catch handler types may shadow one another. */ 268790075Sobrien add_reachable_handler (info, region, region); 268890075Sobrien return RNL_MAYBE_CAUGHT; 268950397Sobrien 269090075Sobrien case ERT_TRY: 269190075Sobrien { 269290075Sobrien struct eh_region *c; 269390075Sobrien enum reachable_code ret = RNL_NOT_CAUGHT; 269450397Sobrien 269590075Sobrien for (c = region->u.try.catch; c ; c = c->u.catch.next_catch) 269690075Sobrien { 269790075Sobrien /* A catch-all handler ends the search. */ 269890075Sobrien /* ??? _Unwind_ForcedUnwind will want outer cleanups 269990075Sobrien to be run as well. */ 270090075Sobrien if (c->u.catch.type_list == NULL) 270190075Sobrien { 270290075Sobrien add_reachable_handler (info, region, c); 270390075Sobrien return RNL_CAUGHT; 270490075Sobrien } 270550397Sobrien 270690075Sobrien if (type_thrown) 270790075Sobrien { 270890075Sobrien /* If we have at least one type match, end the search. */ 270990075Sobrien tree tp_node = c->u.catch.type_list; 271050397Sobrien 271190075Sobrien for (; tp_node; tp_node = TREE_CHAIN (tp_node)) 271290075Sobrien { 271390075Sobrien tree type = TREE_VALUE (tp_node); 271450397Sobrien 271590075Sobrien if (type == type_thrown 271690075Sobrien || (lang_eh_type_covers 271790075Sobrien && (*lang_eh_type_covers) (type, type_thrown))) 271890075Sobrien { 271990075Sobrien add_reachable_handler (info, region, c); 272090075Sobrien return RNL_CAUGHT; 272190075Sobrien } 272290075Sobrien } 272350397Sobrien 272490075Sobrien /* If we have definitive information of a match failure, 272590075Sobrien the catch won't trigger. */ 272690075Sobrien if (lang_eh_type_covers) 272790075Sobrien return RNL_NOT_CAUGHT; 272890075Sobrien } 272950397Sobrien 273090075Sobrien /* At this point, we either don't know what type is thrown or 273190075Sobrien don't have front-end assistance to help deciding if it is 273290075Sobrien covered by one of the types in the list for this region. 273350397Sobrien 273490075Sobrien We'd then like to add this region to the list of reachable 273590075Sobrien handlers since it is indeed potentially reachable based on the 273690075Sobrien information we have. 273750397Sobrien 273890075Sobrien Actually, this handler is for sure not reachable if all the 273990075Sobrien types it matches have already been caught. That is, it is only 274090075Sobrien potentially reachable if at least one of the types it catches 274190075Sobrien has not been previously caught. */ 274250397Sobrien 274390075Sobrien if (! info) 274490075Sobrien ret = RNL_MAYBE_CAUGHT; 274590075Sobrien else 274690075Sobrien { 274790075Sobrien tree tp_node = c->u.catch.type_list; 274890075Sobrien bool maybe_reachable = false; 274950397Sobrien 275090075Sobrien /* Compute the potential reachability of this handler and 275190075Sobrien update the list of types caught at the same time. */ 275290075Sobrien for (; tp_node; tp_node = TREE_CHAIN (tp_node)) 275390075Sobrien { 275490075Sobrien tree type = TREE_VALUE (tp_node); 275590075Sobrien 275690075Sobrien if (! check_handled (info->types_caught, type)) 275790075Sobrien { 275890075Sobrien info->types_caught 275990075Sobrien = tree_cons (NULL, type, info->types_caught); 276090075Sobrien 276190075Sobrien maybe_reachable = true; 276290075Sobrien } 276390075Sobrien } 276490075Sobrien 276590075Sobrien if (maybe_reachable) 276690075Sobrien { 276790075Sobrien add_reachable_handler (info, region, c); 276890075Sobrien 276990075Sobrien /* ??? If the catch type is a base class of every allowed 277090075Sobrien type, then we know we can stop the search. */ 277190075Sobrien ret = RNL_MAYBE_CAUGHT; 277290075Sobrien } 277390075Sobrien } 277490075Sobrien } 277590075Sobrien 277690075Sobrien return ret; 277790075Sobrien } 277890075Sobrien 277990075Sobrien case ERT_ALLOWED_EXCEPTIONS: 278090075Sobrien /* An empty list of types definitely ends the search. */ 278190075Sobrien if (region->u.allowed.type_list == NULL_TREE) 278290075Sobrien { 278390075Sobrien add_reachable_handler (info, region, region); 278490075Sobrien return RNL_CAUGHT; 278590075Sobrien } 278690075Sobrien 278790075Sobrien /* Collect a list of lists of allowed types for use in detecting 278890075Sobrien when a catch may be transformed into a catch-all. */ 278990075Sobrien if (info) 279090075Sobrien info->types_allowed = tree_cons (NULL_TREE, 279190075Sobrien region->u.allowed.type_list, 279290075Sobrien info->types_allowed); 279390075Sobrien 279490075Sobrien /* If we have definitive information about the type hierarchy, 279590075Sobrien then we can tell if the thrown type will pass through the 279690075Sobrien filter. */ 279790075Sobrien if (type_thrown && lang_eh_type_covers) 279890075Sobrien { 279990075Sobrien if (check_handled (region->u.allowed.type_list, type_thrown)) 280090075Sobrien return RNL_NOT_CAUGHT; 280190075Sobrien else 280290075Sobrien { 280390075Sobrien add_reachable_handler (info, region, region); 280490075Sobrien return RNL_CAUGHT; 280590075Sobrien } 280690075Sobrien } 280790075Sobrien 280890075Sobrien add_reachable_handler (info, region, region); 280990075Sobrien return RNL_MAYBE_CAUGHT; 281090075Sobrien 281190075Sobrien case ERT_CATCH: 281290075Sobrien /* Catch regions are handled by their controling try region. */ 281390075Sobrien return RNL_NOT_CAUGHT; 281490075Sobrien 281590075Sobrien case ERT_MUST_NOT_THROW: 281690075Sobrien /* Here we end our search, since no exceptions may propagate. 281790075Sobrien If we've touched down at some landing pad previous, then the 281890075Sobrien explicit function call we generated may be used. Otherwise 281990075Sobrien the call is made by the runtime. */ 282090075Sobrien if (info && info->handlers) 282190075Sobrien { 282290075Sobrien add_reachable_handler (info, region, region); 282390075Sobrien return RNL_CAUGHT; 282490075Sobrien } 282590075Sobrien else 282690075Sobrien return RNL_BLOCKED; 282790075Sobrien 282890075Sobrien case ERT_THROW: 282990075Sobrien case ERT_FIXUP: 283090075Sobrien case ERT_UNKNOWN: 283190075Sobrien /* Shouldn't see these here. */ 283290075Sobrien break; 283390075Sobrien } 283490075Sobrien 283590075Sobrien abort (); 283650397Sobrien} 283750397Sobrien 283890075Sobrien/* Retrieve a list of labels of exception handlers which can be 283990075Sobrien reached by a given insn. */ 284050397Sobrien 284190075Sobrienrtx 284290075Sobrienreachable_handlers (insn) 284350397Sobrien rtx insn; 284450397Sobrien{ 284590075Sobrien struct reachable_info info; 284690075Sobrien struct eh_region *region; 284790075Sobrien tree type_thrown; 284890075Sobrien int region_number; 284950397Sobrien 285090075Sobrien if (GET_CODE (insn) == JUMP_INSN 285190075Sobrien && GET_CODE (PATTERN (insn)) == RESX) 285290075Sobrien region_number = XINT (PATTERN (insn), 0); 285390075Sobrien else 285450397Sobrien { 285590075Sobrien rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 285690075Sobrien if (!note || INTVAL (XEXP (note, 0)) <= 0) 285790075Sobrien return NULL; 285890075Sobrien region_number = INTVAL (XEXP (note, 0)); 285950397Sobrien } 286050397Sobrien 286190075Sobrien memset (&info, 0, sizeof (info)); 286250397Sobrien 286390075Sobrien region = cfun->eh->region_array[region_number]; 286450397Sobrien 286590075Sobrien type_thrown = NULL_TREE; 286690075Sobrien if (GET_CODE (insn) == JUMP_INSN 286790075Sobrien && GET_CODE (PATTERN (insn)) == RESX) 286890075Sobrien { 286990075Sobrien /* A RESX leaves a region instead of entering it. Thus the 287090075Sobrien region itself may have been deleted out from under us. */ 287190075Sobrien if (region == NULL) 287290075Sobrien return NULL; 287390075Sobrien region = region->outer; 287490075Sobrien } 287590075Sobrien else if (region->type == ERT_THROW) 287690075Sobrien { 287790075Sobrien type_thrown = region->u.throw.type; 287890075Sobrien region = region->outer; 287990075Sobrien } 288050397Sobrien 288190075Sobrien for (; region; region = region->outer) 288290075Sobrien if (reachable_next_level (region, type_thrown, &info) >= RNL_CAUGHT) 288390075Sobrien break; 288450397Sobrien 288590075Sobrien return info.handlers; 288690075Sobrien} 288750397Sobrien 288890075Sobrien/* Determine if the given INSN can throw an exception that is caught 288990075Sobrien within the function. */ 289090075Sobrien 289190075Sobrienbool 289290075Sobriencan_throw_internal (insn) 289350397Sobrien rtx insn; 289450397Sobrien{ 289590075Sobrien struct eh_region *region; 289690075Sobrien tree type_thrown; 289790075Sobrien rtx note; 289850397Sobrien 289990075Sobrien if (! INSN_P (insn)) 290090075Sobrien return false; 290150397Sobrien 290290075Sobrien if (GET_CODE (insn) == INSN 290390075Sobrien && GET_CODE (PATTERN (insn)) == SEQUENCE) 290490075Sobrien insn = XVECEXP (PATTERN (insn), 0, 0); 290552284Sobrien 290690075Sobrien if (GET_CODE (insn) == CALL_INSN 290790075Sobrien && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) 290850397Sobrien { 290990075Sobrien int i; 291090075Sobrien for (i = 0; i < 3; ++i) 291150397Sobrien { 291290075Sobrien rtx sub = XEXP (PATTERN (insn), i); 291390075Sobrien for (; sub ; sub = NEXT_INSN (sub)) 291490075Sobrien if (can_throw_internal (sub)) 291590075Sobrien return true; 291650397Sobrien } 291790075Sobrien return false; 291890075Sobrien } 291950397Sobrien 292090075Sobrien /* Every insn that might throw has an EH_REGION note. */ 292190075Sobrien note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 292290075Sobrien if (!note || INTVAL (XEXP (note, 0)) <= 0) 292390075Sobrien return false; 292450397Sobrien 292590075Sobrien region = cfun->eh->region_array[INTVAL (XEXP (note, 0))]; 292690075Sobrien 292790075Sobrien type_thrown = NULL_TREE; 292890075Sobrien if (region->type == ERT_THROW) 292990075Sobrien { 293090075Sobrien type_thrown = region->u.throw.type; 293190075Sobrien region = region->outer; 293250397Sobrien } 293350397Sobrien 293490075Sobrien /* If this exception is ignored by each and every containing region, 293590075Sobrien then control passes straight out. The runtime may handle some 293690075Sobrien regions, which also do not require processing internally. */ 293790075Sobrien for (; region; region = region->outer) 293850397Sobrien { 293990075Sobrien enum reachable_code how = reachable_next_level (region, type_thrown, 0); 294090075Sobrien if (how == RNL_BLOCKED) 294190075Sobrien return false; 294290075Sobrien if (how != RNL_NOT_CAUGHT) 294390075Sobrien return true; 294490075Sobrien } 294550397Sobrien 294690075Sobrien return false; 294790075Sobrien} 294850397Sobrien 294990075Sobrien/* Determine if the given INSN can throw an exception that is 295090075Sobrien visible outside the function. */ 295150397Sobrien 295290075Sobrienbool 295390075Sobriencan_throw_external (insn) 295490075Sobrien rtx insn; 295590075Sobrien{ 295690075Sobrien struct eh_region *region; 295790075Sobrien tree type_thrown; 295890075Sobrien rtx note; 295950397Sobrien 296090075Sobrien if (! INSN_P (insn)) 296190075Sobrien return false; 296290075Sobrien 296390075Sobrien if (GET_CODE (insn) == INSN 296490075Sobrien && GET_CODE (PATTERN (insn)) == SEQUENCE) 296590075Sobrien insn = XVECEXP (PATTERN (insn), 0, 0); 296690075Sobrien 296790075Sobrien if (GET_CODE (insn) == CALL_INSN 296890075Sobrien && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) 296990075Sobrien { 297090075Sobrien int i; 297190075Sobrien for (i = 0; i < 3; ++i) 297290075Sobrien { 297390075Sobrien rtx sub = XEXP (PATTERN (insn), i); 297490075Sobrien for (; sub ; sub = NEXT_INSN (sub)) 297590075Sobrien if (can_throw_external (sub)) 297690075Sobrien return true; 297750397Sobrien } 297890075Sobrien return false; 297950397Sobrien } 298090075Sobrien 298190075Sobrien note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 298290075Sobrien if (!note) 298390075Sobrien { 298490075Sobrien /* Calls (and trapping insns) without notes are outside any 298590075Sobrien exception handling region in this function. We have to 298690075Sobrien assume it might throw. Given that the front end and middle 298790075Sobrien ends mark known NOTHROW functions, this isn't so wildly 298890075Sobrien inaccurate. */ 298990075Sobrien return (GET_CODE (insn) == CALL_INSN 299090075Sobrien || (flag_non_call_exceptions 299190075Sobrien && may_trap_p (PATTERN (insn)))); 299290075Sobrien } 299390075Sobrien if (INTVAL (XEXP (note, 0)) <= 0) 299490075Sobrien return false; 299590075Sobrien 299690075Sobrien region = cfun->eh->region_array[INTVAL (XEXP (note, 0))]; 299790075Sobrien 299890075Sobrien type_thrown = NULL_TREE; 299990075Sobrien if (region->type == ERT_THROW) 300090075Sobrien { 300190075Sobrien type_thrown = region->u.throw.type; 300290075Sobrien region = region->outer; 300390075Sobrien } 300490075Sobrien 300590075Sobrien /* If the exception is caught or blocked by any containing region, 300690075Sobrien then it is not seen by any calling function. */ 300790075Sobrien for (; region ; region = region->outer) 300890075Sobrien if (reachable_next_level (region, type_thrown, NULL) >= RNL_CAUGHT) 300990075Sobrien return false; 301090075Sobrien 301190075Sobrien return true; 301250397Sobrien} 301350397Sobrien 301490075Sobrien/* True if nothing in this function can throw outside this function. */ 301550397Sobrien 301690075Sobrienbool 301790075Sobriennothrow_function_p () 301850397Sobrien{ 301950397Sobrien rtx insn; 302050397Sobrien 302190075Sobrien if (! flag_exceptions) 302290075Sobrien return true; 302390075Sobrien 302450397Sobrien for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 302590075Sobrien if (can_throw_external (insn)) 302690075Sobrien return false; 302790075Sobrien for (insn = current_function_epilogue_delay_list; insn; 302890075Sobrien insn = XEXP (insn, 1)) 302990075Sobrien if (can_throw_external (insn)) 303090075Sobrien return false; 303190075Sobrien 303290075Sobrien return true; 303350397Sobrien} 303490075Sobrien 303550397Sobrien 303690075Sobrien/* Various hooks for unwind library. */ 303750397Sobrien 303850397Sobrien/* Do any necessary initialization to access arbitrary stack frames. 303950397Sobrien On the SPARC, this means flushing the register windows. */ 304050397Sobrien 304150397Sobrienvoid 304250397Sobrienexpand_builtin_unwind_init () 304350397Sobrien{ 304450397Sobrien /* Set this so all the registers get saved in our frame; we need to be 304590075Sobrien able to copy the saved values for any registers from frames we unwind. */ 304650397Sobrien current_function_has_nonlocal_label = 1; 304750397Sobrien 304850397Sobrien#ifdef SETUP_FRAME_ADDRESSES 304950397Sobrien SETUP_FRAME_ADDRESSES (); 305050397Sobrien#endif 305150397Sobrien} 305250397Sobrien 305390075Sobrienrtx 305490075Sobrienexpand_builtin_eh_return_data_regno (arglist) 305590075Sobrien tree arglist; 305690075Sobrien{ 305790075Sobrien tree which = TREE_VALUE (arglist); 305890075Sobrien unsigned HOST_WIDE_INT iwhich; 305990075Sobrien 306090075Sobrien if (TREE_CODE (which) != INTEGER_CST) 306190075Sobrien { 306290075Sobrien error ("argument of `__builtin_eh_return_regno' must be constant"); 306390075Sobrien return constm1_rtx; 306490075Sobrien } 306590075Sobrien 306690075Sobrien iwhich = tree_low_cst (which, 1); 306790075Sobrien iwhich = EH_RETURN_DATA_REGNO (iwhich); 306890075Sobrien if (iwhich == INVALID_REGNUM) 306990075Sobrien return constm1_rtx; 307090075Sobrien 307190075Sobrien#ifdef DWARF_FRAME_REGNUM 307290075Sobrien iwhich = DWARF_FRAME_REGNUM (iwhich); 307390075Sobrien#else 307490075Sobrien iwhich = DBX_REGISTER_NUMBER (iwhich); 307590075Sobrien#endif 307690075Sobrien 307790075Sobrien return GEN_INT (iwhich); 307890075Sobrien} 307990075Sobrien 308050397Sobrien/* Given a value extracted from the return address register or stack slot, 308150397Sobrien return the actual address encoded in that value. */ 308250397Sobrien 308350397Sobrienrtx 308450397Sobrienexpand_builtin_extract_return_addr (addr_tree) 308550397Sobrien tree addr_tree; 308650397Sobrien{ 308750397Sobrien rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0); 308890075Sobrien 308990075Sobrien /* First mask out any unwanted bits. */ 309090075Sobrien#ifdef MASK_RETURN_ADDR 309190075Sobrien expand_and (addr, MASK_RETURN_ADDR, addr); 309290075Sobrien#endif 309390075Sobrien 309490075Sobrien /* Then adjust to find the real return address. */ 309590075Sobrien#if defined (RETURN_ADDR_OFFSET) 309690075Sobrien addr = plus_constant (addr, RETURN_ADDR_OFFSET); 309790075Sobrien#endif 309890075Sobrien 309990075Sobrien return addr; 310050397Sobrien} 310150397Sobrien 310250397Sobrien/* Given an actual address in addr_tree, do any necessary encoding 310350397Sobrien and return the value to be stored in the return address register or 310450397Sobrien stack slot so the epilogue will return to that address. */ 310550397Sobrien 310650397Sobrienrtx 310750397Sobrienexpand_builtin_frob_return_addr (addr_tree) 310850397Sobrien tree addr_tree; 310950397Sobrien{ 311090075Sobrien rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, 0); 311190075Sobrien 311290075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED 311390075Sobrien if (GET_MODE (addr) != Pmode) 311490075Sobrien addr = convert_memory_address (Pmode, addr); 311590075Sobrien#endif 311690075Sobrien 311750397Sobrien#ifdef RETURN_ADDR_OFFSET 311890075Sobrien addr = force_reg (Pmode, addr); 311950397Sobrien addr = plus_constant (addr, -RETURN_ADDR_OFFSET); 312050397Sobrien#endif 312190075Sobrien 312250397Sobrien return addr; 312350397Sobrien} 312450397Sobrien 312590075Sobrien/* Set up the epilogue with the magic bits we'll need to return to the 312690075Sobrien exception handler. */ 312750397Sobrien 312890075Sobrienvoid 312990075Sobrienexpand_builtin_eh_return (stackadj_tree, handler_tree) 313090075Sobrien tree stackadj_tree, handler_tree; 313190075Sobrien{ 313290075Sobrien rtx stackadj, handler; 313350397Sobrien 313490075Sobrien stackadj = expand_expr (stackadj_tree, cfun->eh->ehr_stackadj, VOIDmode, 0); 313590075Sobrien handler = expand_expr (handler_tree, cfun->eh->ehr_handler, VOIDmode, 0); 313650397Sobrien 313790075Sobrien#ifdef POINTERS_EXTEND_UNSIGNED 313890075Sobrien if (GET_MODE (stackadj) != Pmode) 313990075Sobrien stackadj = convert_memory_address (Pmode, stackadj); 314050397Sobrien 314190075Sobrien if (GET_MODE (handler) != Pmode) 314290075Sobrien handler = convert_memory_address (Pmode, handler); 314350397Sobrien#endif 314450397Sobrien 314590075Sobrien if (! cfun->eh->ehr_label) 314690075Sobrien { 314790075Sobrien cfun->eh->ehr_stackadj = copy_to_reg (stackadj); 314890075Sobrien cfun->eh->ehr_handler = copy_to_reg (handler); 314990075Sobrien cfun->eh->ehr_label = gen_label_rtx (); 315090075Sobrien } 315150397Sobrien else 315290075Sobrien { 315390075Sobrien if (stackadj != cfun->eh->ehr_stackadj) 315490075Sobrien emit_move_insn (cfun->eh->ehr_stackadj, stackadj); 315590075Sobrien if (handler != cfun->eh->ehr_handler) 315690075Sobrien emit_move_insn (cfun->eh->ehr_handler, handler); 315790075Sobrien } 315850397Sobrien 315990075Sobrien emit_jump (cfun->eh->ehr_label); 316090075Sobrien} 316190075Sobrien 316290075Sobrienvoid 316390075Sobrienexpand_eh_return () 316490075Sobrien{ 316590075Sobrien rtx sa, ra, around_label; 316690075Sobrien 316790075Sobrien if (! cfun->eh->ehr_label) 316890075Sobrien return; 316990075Sobrien 317090075Sobrien sa = EH_RETURN_STACKADJ_RTX; 317190075Sobrien if (! sa) 317250397Sobrien { 317390075Sobrien error ("__builtin_eh_return not supported on this target"); 317490075Sobrien return; 317590075Sobrien } 317650397Sobrien 317790075Sobrien current_function_calls_eh_return = 1; 317890075Sobrien 317990075Sobrien around_label = gen_label_rtx (); 318090075Sobrien emit_move_insn (sa, const0_rtx); 318190075Sobrien emit_jump (around_label); 318290075Sobrien 318390075Sobrien emit_label (cfun->eh->ehr_label); 318490075Sobrien clobber_return_register (); 318590075Sobrien 318690075Sobrien#ifdef HAVE_eh_return 318790075Sobrien if (HAVE_eh_return) 318890075Sobrien emit_insn (gen_eh_return (cfun->eh->ehr_stackadj, cfun->eh->ehr_handler)); 318990075Sobrien else 319090075Sobrien#endif 319190075Sobrien { 319290075Sobrien ra = EH_RETURN_HANDLER_RTX; 319390075Sobrien if (! ra) 319490075Sobrien { 319590075Sobrien error ("__builtin_eh_return not supported on this target"); 319690075Sobrien ra = gen_reg_rtx (Pmode); 319790075Sobrien } 319890075Sobrien 319990075Sobrien emit_move_insn (sa, cfun->eh->ehr_stackadj); 320090075Sobrien emit_move_insn (ra, cfun->eh->ehr_handler); 320150397Sobrien } 320250397Sobrien 320390075Sobrien emit_label (around_label); 320490075Sobrien} 320590075Sobrien 320690075Sobrien/* In the following functions, we represent entries in the action table 320790075Sobrien as 1-based indices. Special cases are: 320852284Sobrien 320990075Sobrien 0: null action record, non-null landing pad; implies cleanups 321090075Sobrien -1: null action record, null landing pad; implies no action 321190075Sobrien -2: no call-site entry; implies must_not_throw 321290075Sobrien -3: we have yet to process outer regions 321352284Sobrien 321490075Sobrien Further, no special cases apply to the "next" field of the record. 321590075Sobrien For next, 0 means end of list. */ 321690075Sobrien 321790075Sobrienstruct action_record 321890075Sobrien{ 321990075Sobrien int offset; 322090075Sobrien int filter; 322190075Sobrien int next; 322290075Sobrien}; 322390075Sobrien 322490075Sobrienstatic int 322590075Sobrienaction_record_eq (pentry, pdata) 322690075Sobrien const PTR pentry; 322790075Sobrien const PTR pdata; 322890075Sobrien{ 322990075Sobrien const struct action_record *entry = (const struct action_record *) pentry; 323090075Sobrien const struct action_record *data = (const struct action_record *) pdata; 323190075Sobrien return entry->filter == data->filter && entry->next == data->next; 323250397Sobrien} 323350397Sobrien 323490075Sobrienstatic hashval_t 323590075Sobrienaction_record_hash (pentry) 323690075Sobrien const PTR pentry; 323790075Sobrien{ 323890075Sobrien const struct action_record *entry = (const struct action_record *) pentry; 323990075Sobrien return entry->next * 1009 + entry->filter; 324090075Sobrien} 324150397Sobrien 324290075Sobrienstatic int 324390075Sobrienadd_action_record (ar_hash, filter, next) 324490075Sobrien htab_t ar_hash; 324590075Sobrien int filter, next; 324650397Sobrien{ 324790075Sobrien struct action_record **slot, *new, tmp; 324890075Sobrien 324990075Sobrien tmp.filter = filter; 325090075Sobrien tmp.next = next; 325190075Sobrien slot = (struct action_record **) htab_find_slot (ar_hash, &tmp, INSERT); 325290075Sobrien 325390075Sobrien if ((new = *slot) == NULL) 325490075Sobrien { 325590075Sobrien new = (struct action_record *) xmalloc (sizeof (*new)); 325690075Sobrien new->offset = VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) + 1; 325790075Sobrien new->filter = filter; 325890075Sobrien new->next = next; 325990075Sobrien *slot = new; 326090075Sobrien 326190075Sobrien /* The filter value goes in untouched. The link to the next 326290075Sobrien record is a "self-relative" byte offset, or zero to indicate 326390075Sobrien that there is no next record. So convert the absolute 1 based 326490075Sobrien indices we've been carrying around into a displacement. */ 326590075Sobrien 326690075Sobrien push_sleb128 (&cfun->eh->action_record_data, filter); 326790075Sobrien if (next) 326890075Sobrien next -= VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) + 1; 326990075Sobrien push_sleb128 (&cfun->eh->action_record_data, next); 327090075Sobrien } 327190075Sobrien 327290075Sobrien return new->offset; 327350397Sobrien} 327450397Sobrien 327590075Sobrienstatic int 327690075Sobriencollect_one_action_chain (ar_hash, region) 327790075Sobrien htab_t ar_hash; 327890075Sobrien struct eh_region *region; 327990075Sobrien{ 328090075Sobrien struct eh_region *c; 328190075Sobrien int next; 328250397Sobrien 328390075Sobrien /* If we've reached the top of the region chain, then we have 328490075Sobrien no actions, and require no landing pad. */ 328590075Sobrien if (region == NULL) 328690075Sobrien return -1; 328790075Sobrien 328890075Sobrien switch (region->type) 328990075Sobrien { 329090075Sobrien case ERT_CLEANUP: 329190075Sobrien /* A cleanup adds a zero filter to the beginning of the chain, but 329290075Sobrien there are special cases to look out for. If there are *only* 329390075Sobrien cleanups along a path, then it compresses to a zero action. 329490075Sobrien Further, if there are multiple cleanups along a path, we only 329590075Sobrien need to represent one of them, as that is enough to trigger 329690075Sobrien entry to the landing pad at runtime. */ 329790075Sobrien next = collect_one_action_chain (ar_hash, region->outer); 329890075Sobrien if (next <= 0) 329990075Sobrien return 0; 330090075Sobrien for (c = region->outer; c ; c = c->outer) 330190075Sobrien if (c->type == ERT_CLEANUP) 330290075Sobrien return next; 330390075Sobrien return add_action_record (ar_hash, 0, next); 330490075Sobrien 330590075Sobrien case ERT_TRY: 330690075Sobrien /* Process the associated catch regions in reverse order. 330790075Sobrien If there's a catch-all handler, then we don't need to 330890075Sobrien search outer regions. Use a magic -3 value to record 330990075Sobrien that we haven't done the outer search. */ 331090075Sobrien next = -3; 331190075Sobrien for (c = region->u.try.last_catch; c ; c = c->u.catch.prev_catch) 331290075Sobrien { 331390075Sobrien if (c->u.catch.type_list == NULL) 331490075Sobrien { 331590075Sobrien /* Retrieve the filter from the head of the filter list 331690075Sobrien where we have stored it (see assign_filter_values). */ 331790075Sobrien int filter 331890075Sobrien = TREE_INT_CST_LOW (TREE_VALUE (c->u.catch.filter_list)); 331990075Sobrien 332090075Sobrien next = add_action_record (ar_hash, filter, 0); 332190075Sobrien } 332290075Sobrien else 332390075Sobrien { 332490075Sobrien /* Once the outer search is done, trigger an action record for 332590075Sobrien each filter we have. */ 332690075Sobrien tree flt_node; 332790075Sobrien 332890075Sobrien if (next == -3) 332990075Sobrien { 333090075Sobrien next = collect_one_action_chain (ar_hash, region->outer); 333190075Sobrien 333290075Sobrien /* If there is no next action, terminate the chain. */ 333390075Sobrien if (next == -1) 333490075Sobrien next = 0; 333590075Sobrien /* If all outer actions are cleanups or must_not_throw, 333690075Sobrien we'll have no action record for it, since we had wanted 333790075Sobrien to encode these states in the call-site record directly. 333890075Sobrien Add a cleanup action to the chain to catch these. */ 333990075Sobrien else if (next <= 0) 334090075Sobrien next = add_action_record (ar_hash, 0, 0); 334190075Sobrien } 334290075Sobrien 334390075Sobrien flt_node = c->u.catch.filter_list; 334490075Sobrien for (; flt_node; flt_node = TREE_CHAIN (flt_node)) 334590075Sobrien { 334690075Sobrien int filter = TREE_INT_CST_LOW (TREE_VALUE (flt_node)); 334790075Sobrien next = add_action_record (ar_hash, filter, next); 334890075Sobrien } 334990075Sobrien } 335090075Sobrien } 335190075Sobrien return next; 335290075Sobrien 335390075Sobrien case ERT_ALLOWED_EXCEPTIONS: 335490075Sobrien /* An exception specification adds its filter to the 335590075Sobrien beginning of the chain. */ 335690075Sobrien next = collect_one_action_chain (ar_hash, region->outer); 335790075Sobrien return add_action_record (ar_hash, region->u.allowed.filter, 335890075Sobrien next < 0 ? 0 : next); 335990075Sobrien 336090075Sobrien case ERT_MUST_NOT_THROW: 336190075Sobrien /* A must-not-throw region with no inner handlers or cleanups 336290075Sobrien requires no call-site entry. Note that this differs from 336390075Sobrien the no handler or cleanup case in that we do require an lsda 336490075Sobrien to be generated. Return a magic -2 value to record this. */ 336590075Sobrien return -2; 336690075Sobrien 336790075Sobrien case ERT_CATCH: 336890075Sobrien case ERT_THROW: 336990075Sobrien /* CATCH regions are handled in TRY above. THROW regions are 337090075Sobrien for optimization information only and produce no output. */ 337190075Sobrien return collect_one_action_chain (ar_hash, region->outer); 337290075Sobrien 337390075Sobrien default: 337490075Sobrien abort (); 337590075Sobrien } 337690075Sobrien} 337790075Sobrien 337890075Sobrienstatic int 337990075Sobrienadd_call_site (landing_pad, action) 338090075Sobrien rtx landing_pad; 338190075Sobrien int action; 338250397Sobrien{ 338390075Sobrien struct call_site_record *data = cfun->eh->call_site_data; 338490075Sobrien int used = cfun->eh->call_site_data_used; 338590075Sobrien int size = cfun->eh->call_site_data_size; 338650397Sobrien 338790075Sobrien if (used >= size) 338890075Sobrien { 338990075Sobrien size = (size ? size * 2 : 64); 339090075Sobrien data = (struct call_site_record *) 339190075Sobrien xrealloc (data, sizeof (*data) * size); 339290075Sobrien cfun->eh->call_site_data = data; 339390075Sobrien cfun->eh->call_site_data_size = size; 339490075Sobrien } 339590075Sobrien 339690075Sobrien data[used].landing_pad = landing_pad; 339790075Sobrien data[used].action = action; 339890075Sobrien 339990075Sobrien cfun->eh->call_site_data_used = used + 1; 340090075Sobrien 340190075Sobrien return used + call_site_base; 340250397Sobrien} 340350397Sobrien 340490075Sobrien/* Turn REG_EH_REGION notes back into NOTE_INSN_EH_REGION notes. 340590075Sobrien The new note numbers will not refer to region numbers, but 340690075Sobrien instead to call site entries. */ 340790075Sobrien 340852284Sobrienvoid 340990075Sobrienconvert_to_eh_region_ranges () 341050397Sobrien{ 341190075Sobrien rtx insn, iter, note; 341290075Sobrien htab_t ar_hash; 341390075Sobrien int last_action = -3; 341490075Sobrien rtx last_action_insn = NULL_RTX; 341590075Sobrien rtx last_landing_pad = NULL_RTX; 341690075Sobrien rtx first_no_action_insn = NULL_RTX; 341790075Sobrien int call_site = 0; 341850397Sobrien 341990075Sobrien if (USING_SJLJ_EXCEPTIONS || cfun->eh->region_tree == NULL) 342052284Sobrien return; 342150397Sobrien 342290075Sobrien VARRAY_UCHAR_INIT (cfun->eh->action_record_data, 64, "action_record_data"); 342350397Sobrien 342490075Sobrien ar_hash = htab_create (31, action_record_hash, action_record_eq, free); 342550397Sobrien 342690075Sobrien for (iter = get_insns (); iter ; iter = NEXT_INSN (iter)) 342790075Sobrien if (INSN_P (iter)) 342890075Sobrien { 342990075Sobrien struct eh_region *region; 343090075Sobrien int this_action; 343190075Sobrien rtx this_landing_pad; 343250397Sobrien 343390075Sobrien insn = iter; 343490075Sobrien if (GET_CODE (insn) == INSN 343590075Sobrien && GET_CODE (PATTERN (insn)) == SEQUENCE) 343690075Sobrien insn = XVECEXP (PATTERN (insn), 0, 0); 343750397Sobrien 343890075Sobrien note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 343990075Sobrien if (!note) 344090075Sobrien { 344190075Sobrien if (! (GET_CODE (insn) == CALL_INSN 344290075Sobrien || (flag_non_call_exceptions 344390075Sobrien && may_trap_p (PATTERN (insn))))) 344490075Sobrien continue; 344590075Sobrien this_action = -1; 344690075Sobrien region = NULL; 344790075Sobrien } 344890075Sobrien else 344990075Sobrien { 345090075Sobrien if (INTVAL (XEXP (note, 0)) <= 0) 345190075Sobrien continue; 345290075Sobrien region = cfun->eh->region_array[INTVAL (XEXP (note, 0))]; 345390075Sobrien this_action = collect_one_action_chain (ar_hash, region); 345490075Sobrien } 345550397Sobrien 345690075Sobrien /* Existence of catch handlers, or must-not-throw regions 345790075Sobrien implies that an lsda is needed (even if empty). */ 345890075Sobrien if (this_action != -1) 345990075Sobrien cfun->uses_eh_lsda = 1; 346050397Sobrien 346190075Sobrien /* Delay creation of region notes for no-action regions 346290075Sobrien until we're sure that an lsda will be required. */ 346390075Sobrien else if (last_action == -3) 346490075Sobrien { 346590075Sobrien first_no_action_insn = iter; 346690075Sobrien last_action = -1; 346790075Sobrien } 346850397Sobrien 346990075Sobrien /* Cleanups and handlers may share action chains but not 347090075Sobrien landing pads. Collect the landing pad for this region. */ 347190075Sobrien if (this_action >= 0) 347290075Sobrien { 347390075Sobrien struct eh_region *o; 347490075Sobrien for (o = region; ! o->landing_pad ; o = o->outer) 347590075Sobrien continue; 347690075Sobrien this_landing_pad = o->landing_pad; 347790075Sobrien } 347890075Sobrien else 347990075Sobrien this_landing_pad = NULL_RTX; 348050397Sobrien 348190075Sobrien /* Differing actions or landing pads implies a change in call-site 348290075Sobrien info, which implies some EH_REGION note should be emitted. */ 348390075Sobrien if (last_action != this_action 348490075Sobrien || last_landing_pad != this_landing_pad) 348590075Sobrien { 348690075Sobrien /* If we'd not seen a previous action (-3) or the previous 348790075Sobrien action was must-not-throw (-2), then we do not need an 348890075Sobrien end note. */ 348990075Sobrien if (last_action >= -1) 349090075Sobrien { 349190075Sobrien /* If we delayed the creation of the begin, do it now. */ 349290075Sobrien if (first_no_action_insn) 349390075Sobrien { 349490075Sobrien call_site = add_call_site (NULL_RTX, 0); 349590075Sobrien note = emit_note_before (NOTE_INSN_EH_REGION_BEG, 349690075Sobrien first_no_action_insn); 349790075Sobrien NOTE_EH_HANDLER (note) = call_site; 349890075Sobrien first_no_action_insn = NULL_RTX; 349990075Sobrien } 350050397Sobrien 350190075Sobrien note = emit_note_after (NOTE_INSN_EH_REGION_END, 350290075Sobrien last_action_insn); 350390075Sobrien NOTE_EH_HANDLER (note) = call_site; 350490075Sobrien } 350552284Sobrien 350690075Sobrien /* If the new action is must-not-throw, then no region notes 350790075Sobrien are created. */ 350890075Sobrien if (this_action >= -1) 350990075Sobrien { 351090075Sobrien call_site = add_call_site (this_landing_pad, 351190075Sobrien this_action < 0 ? 0 : this_action); 351290075Sobrien note = emit_note_before (NOTE_INSN_EH_REGION_BEG, iter); 351390075Sobrien NOTE_EH_HANDLER (note) = call_site; 351490075Sobrien } 351552284Sobrien 351690075Sobrien last_action = this_action; 351790075Sobrien last_landing_pad = this_landing_pad; 351890075Sobrien } 351990075Sobrien last_action_insn = iter; 352090075Sobrien } 352152284Sobrien 352290075Sobrien if (last_action >= -1 && ! first_no_action_insn) 352390075Sobrien { 352490075Sobrien note = emit_note_after (NOTE_INSN_EH_REGION_END, last_action_insn); 352590075Sobrien NOTE_EH_HANDLER (note) = call_site; 352690075Sobrien } 352752284Sobrien 352890075Sobrien htab_delete (ar_hash); 352950397Sobrien} 353090075Sobrien 353150397Sobrien 353290075Sobrienstatic void 353390075Sobrienpush_uleb128 (data_area, value) 353490075Sobrien varray_type *data_area; 353590075Sobrien unsigned int value; 353690075Sobrien{ 353790075Sobrien do 353890075Sobrien { 353990075Sobrien unsigned char byte = value & 0x7f; 354090075Sobrien value >>= 7; 354190075Sobrien if (value) 354290075Sobrien byte |= 0x80; 354390075Sobrien VARRAY_PUSH_UCHAR (*data_area, byte); 354490075Sobrien } 354590075Sobrien while (value); 354690075Sobrien} 354750397Sobrien 354890075Sobrienstatic void 354990075Sobrienpush_sleb128 (data_area, value) 355090075Sobrien varray_type *data_area; 355190075Sobrien int value; 355290075Sobrien{ 355390075Sobrien unsigned char byte; 355490075Sobrien int more; 355550397Sobrien 355690075Sobrien do 355790075Sobrien { 355890075Sobrien byte = value & 0x7f; 355990075Sobrien value >>= 7; 356090075Sobrien more = ! ((value == 0 && (byte & 0x40) == 0) 356190075Sobrien || (value == -1 && (byte & 0x40) != 0)); 356290075Sobrien if (more) 356390075Sobrien byte |= 0x80; 356490075Sobrien VARRAY_PUSH_UCHAR (*data_area, byte); 356590075Sobrien } 356690075Sobrien while (more); 356790075Sobrien} 356850397Sobrien 356990075Sobrien 357090075Sobrien#ifndef HAVE_AS_LEB128 357190075Sobrienstatic int 357290075Sobriendw2_size_of_call_site_table () 357350397Sobrien{ 357490075Sobrien int n = cfun->eh->call_site_data_used; 357590075Sobrien int size = n * (4 + 4 + 4); 357690075Sobrien int i; 357750397Sobrien 357890075Sobrien for (i = 0; i < n; ++i) 357950397Sobrien { 358090075Sobrien struct call_site_record *cs = &cfun->eh->call_site_data[i]; 358190075Sobrien size += size_of_uleb128 (cs->action); 358250397Sobrien } 358390075Sobrien 358490075Sobrien return size; 358550397Sobrien} 358650397Sobrien 358790075Sobrienstatic int 358890075Sobriensjlj_size_of_call_site_table () 358990075Sobrien{ 359090075Sobrien int n = cfun->eh->call_site_data_used; 359190075Sobrien int size = 0; 359290075Sobrien int i; 359350397Sobrien 359490075Sobrien for (i = 0; i < n; ++i) 359590075Sobrien { 359690075Sobrien struct call_site_record *cs = &cfun->eh->call_site_data[i]; 359790075Sobrien size += size_of_uleb128 (INTVAL (cs->landing_pad)); 359890075Sobrien size += size_of_uleb128 (cs->action); 359990075Sobrien } 360090075Sobrien 360190075Sobrien return size; 360290075Sobrien} 360390075Sobrien#endif 360490075Sobrien 360590075Sobrienstatic void 360690075Sobriendw2_output_call_site_table () 360750397Sobrien{ 360890075Sobrien const char *const function_start_lab 360990075Sobrien = IDENTIFIER_POINTER (current_function_func_begin_label); 361090075Sobrien int n = cfun->eh->call_site_data_used; 361190075Sobrien int i; 361250397Sobrien 361390075Sobrien for (i = 0; i < n; ++i) 361450397Sobrien { 361590075Sobrien struct call_site_record *cs = &cfun->eh->call_site_data[i]; 361690075Sobrien char reg_start_lab[32]; 361790075Sobrien char reg_end_lab[32]; 361890075Sobrien char landing_pad_lab[32]; 361990075Sobrien 362090075Sobrien ASM_GENERATE_INTERNAL_LABEL (reg_start_lab, "LEHB", call_site_base + i); 362190075Sobrien ASM_GENERATE_INTERNAL_LABEL (reg_end_lab, "LEHE", call_site_base + i); 362290075Sobrien 362390075Sobrien if (cs->landing_pad) 362490075Sobrien ASM_GENERATE_INTERNAL_LABEL (landing_pad_lab, "L", 362590075Sobrien CODE_LABEL_NUMBER (cs->landing_pad)); 362690075Sobrien 362790075Sobrien /* ??? Perhaps use insn length scaling if the assembler supports 362890075Sobrien generic arithmetic. */ 362990075Sobrien /* ??? Perhaps use attr_length to choose data1 or data2 instead of 363090075Sobrien data4 if the function is small enough. */ 363190075Sobrien#ifdef HAVE_AS_LEB128 363290075Sobrien dw2_asm_output_delta_uleb128 (reg_start_lab, function_start_lab, 363390075Sobrien "region %d start", i); 363490075Sobrien dw2_asm_output_delta_uleb128 (reg_end_lab, reg_start_lab, 363590075Sobrien "length"); 363690075Sobrien if (cs->landing_pad) 363790075Sobrien dw2_asm_output_delta_uleb128 (landing_pad_lab, function_start_lab, 363890075Sobrien "landing pad"); 363990075Sobrien else 364090075Sobrien dw2_asm_output_data_uleb128 (0, "landing pad"); 364190075Sobrien#else 364290075Sobrien dw2_asm_output_delta (4, reg_start_lab, function_start_lab, 364390075Sobrien "region %d start", i); 364490075Sobrien dw2_asm_output_delta (4, reg_end_lab, reg_start_lab, "length"); 364590075Sobrien if (cs->landing_pad) 364690075Sobrien dw2_asm_output_delta (4, landing_pad_lab, function_start_lab, 364790075Sobrien "landing pad"); 364890075Sobrien else 364990075Sobrien dw2_asm_output_data (4, 0, "landing pad"); 365090075Sobrien#endif 365190075Sobrien dw2_asm_output_data_uleb128 (cs->action, "action"); 365250397Sobrien } 365390075Sobrien 365490075Sobrien call_site_base += n; 365550397Sobrien} 365650397Sobrien 365790075Sobrienstatic void 365890075Sobriensjlj_output_call_site_table () 365990075Sobrien{ 366090075Sobrien int n = cfun->eh->call_site_data_used; 366190075Sobrien int i; 366250397Sobrien 366390075Sobrien for (i = 0; i < n; ++i) 366490075Sobrien { 366590075Sobrien struct call_site_record *cs = &cfun->eh->call_site_data[i]; 366690075Sobrien 366790075Sobrien dw2_asm_output_data_uleb128 (INTVAL (cs->landing_pad), 366890075Sobrien "region %d landing pad", i); 366990075Sobrien dw2_asm_output_data_uleb128 (cs->action, "action"); 367090075Sobrien } 367190075Sobrien 367290075Sobrien call_site_base += n; 367390075Sobrien} 367490075Sobrien 367590075Sobrienvoid 367690075Sobrienoutput_function_exception_table () 367750397Sobrien{ 367890075Sobrien int tt_format, cs_format, lp_format, i, n; 367990075Sobrien#ifdef HAVE_AS_LEB128 368090075Sobrien char ttype_label[32]; 368190075Sobrien char cs_after_size_label[32]; 368290075Sobrien char cs_end_label[32]; 368390075Sobrien#else 368490075Sobrien int call_site_len; 368590075Sobrien#endif 368690075Sobrien int have_tt_data; 368790075Sobrien int funcdef_number; 368890075Sobrien int tt_format_size = 0; 368950397Sobrien 369090075Sobrien /* Not all functions need anything. */ 369190075Sobrien if (! cfun->uses_eh_lsda) 369250397Sobrien return; 369350397Sobrien 369490075Sobrien funcdef_number = (USING_SJLJ_EXCEPTIONS 369590075Sobrien ? sjlj_funcdef_number 369690075Sobrien : current_funcdef_number); 369750397Sobrien 369890075Sobrien#ifdef IA64_UNWIND_INFO 369990075Sobrien fputs ("\t.personality\t", asm_out_file); 370090075Sobrien output_addr_const (asm_out_file, eh_personality_libfunc); 370190075Sobrien fputs ("\n\t.handlerdata\n", asm_out_file); 370290075Sobrien /* Note that varasm still thinks we're in the function's code section. 370390075Sobrien The ".endp" directive that will immediately follow will take us back. */ 370490075Sobrien#else 370590075Sobrien (*targetm.asm_out.exception_section) (); 370690075Sobrien#endif 370750397Sobrien 370890075Sobrien have_tt_data = (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) > 0 370990075Sobrien || VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) > 0); 371050397Sobrien 371190075Sobrien /* Indicate the format of the @TType entries. */ 371290075Sobrien if (! have_tt_data) 371390075Sobrien tt_format = DW_EH_PE_omit; 371490075Sobrien else 371590075Sobrien { 371690075Sobrien tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1); 371790075Sobrien#ifdef HAVE_AS_LEB128 371890075Sobrien ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT", funcdef_number); 371990075Sobrien#endif 372090075Sobrien tt_format_size = size_of_encoded_value (tt_format); 372150397Sobrien 372290075Sobrien assemble_align (tt_format_size * BITS_PER_UNIT); 372390075Sobrien } 372450397Sobrien 372590075Sobrien ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LLSDA", funcdef_number); 372650397Sobrien 372790075Sobrien /* The LSDA header. */ 372850397Sobrien 372990075Sobrien /* Indicate the format of the landing pad start pointer. An omitted 373090075Sobrien field implies @LPStart == @Start. */ 373190075Sobrien /* Currently we always put @LPStart == @Start. This field would 373290075Sobrien be most useful in moving the landing pads completely out of 373390075Sobrien line to another section, but it could also be used to minimize 373490075Sobrien the size of uleb128 landing pad offsets. */ 373590075Sobrien lp_format = DW_EH_PE_omit; 373690075Sobrien dw2_asm_output_data (1, lp_format, "@LPStart format (%s)", 373790075Sobrien eh_data_format_name (lp_format)); 373850397Sobrien 373990075Sobrien /* @LPStart pointer would go here. */ 374050397Sobrien 374190075Sobrien dw2_asm_output_data (1, tt_format, "@TType format (%s)", 374290075Sobrien eh_data_format_name (tt_format)); 374350397Sobrien 374490075Sobrien#ifndef HAVE_AS_LEB128 374590075Sobrien if (USING_SJLJ_EXCEPTIONS) 374690075Sobrien call_site_len = sjlj_size_of_call_site_table (); 374790075Sobrien else 374890075Sobrien call_site_len = dw2_size_of_call_site_table (); 374990075Sobrien#endif 375090075Sobrien 375190075Sobrien /* A pc-relative 4-byte displacement to the @TType data. */ 375290075Sobrien if (have_tt_data) 375390075Sobrien { 375490075Sobrien#ifdef HAVE_AS_LEB128 375590075Sobrien char ttype_after_disp_label[32]; 375690075Sobrien ASM_GENERATE_INTERNAL_LABEL (ttype_after_disp_label, "LLSDATTD", 375790075Sobrien funcdef_number); 375890075Sobrien dw2_asm_output_delta_uleb128 (ttype_label, ttype_after_disp_label, 375990075Sobrien "@TType base offset"); 376090075Sobrien ASM_OUTPUT_LABEL (asm_out_file, ttype_after_disp_label); 376190075Sobrien#else 376290075Sobrien /* Ug. Alignment queers things. */ 376390075Sobrien unsigned int before_disp, after_disp, last_disp, disp; 376490075Sobrien 376590075Sobrien before_disp = 1 + 1; 376690075Sobrien after_disp = (1 + size_of_uleb128 (call_site_len) 376790075Sobrien + call_site_len 376890075Sobrien + VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) 376990075Sobrien + (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) 377090075Sobrien * tt_format_size)); 377190075Sobrien 377290075Sobrien disp = after_disp; 377390075Sobrien do 377490075Sobrien { 377590075Sobrien unsigned int disp_size, pad; 377690075Sobrien 377790075Sobrien last_disp = disp; 377890075Sobrien disp_size = size_of_uleb128 (disp); 377990075Sobrien pad = before_disp + disp_size + after_disp; 378090075Sobrien if (pad % tt_format_size) 378190075Sobrien pad = tt_format_size - (pad % tt_format_size); 378290075Sobrien else 378390075Sobrien pad = 0; 378490075Sobrien disp = after_disp + pad; 378590075Sobrien } 378690075Sobrien while (disp != last_disp); 378790075Sobrien 378890075Sobrien dw2_asm_output_data_uleb128 (disp, "@TType base offset"); 378990075Sobrien#endif 379090075Sobrien } 379190075Sobrien 379290075Sobrien /* Indicate the format of the call-site offsets. */ 379390075Sobrien#ifdef HAVE_AS_LEB128 379490075Sobrien cs_format = DW_EH_PE_uleb128; 379590075Sobrien#else 379690075Sobrien cs_format = DW_EH_PE_udata4; 379790075Sobrien#endif 379890075Sobrien dw2_asm_output_data (1, cs_format, "call-site format (%s)", 379990075Sobrien eh_data_format_name (cs_format)); 380090075Sobrien 380190075Sobrien#ifdef HAVE_AS_LEB128 380290075Sobrien ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label, "LLSDACSB", 380390075Sobrien funcdef_number); 380490075Sobrien ASM_GENERATE_INTERNAL_LABEL (cs_end_label, "LLSDACSE", 380590075Sobrien funcdef_number); 380690075Sobrien dw2_asm_output_delta_uleb128 (cs_end_label, cs_after_size_label, 380790075Sobrien "Call-site table length"); 380890075Sobrien ASM_OUTPUT_LABEL (asm_out_file, cs_after_size_label); 380990075Sobrien if (USING_SJLJ_EXCEPTIONS) 381090075Sobrien sjlj_output_call_site_table (); 381190075Sobrien else 381290075Sobrien dw2_output_call_site_table (); 381390075Sobrien ASM_OUTPUT_LABEL (asm_out_file, cs_end_label); 381490075Sobrien#else 381590075Sobrien dw2_asm_output_data_uleb128 (call_site_len,"Call-site table length"); 381690075Sobrien if (USING_SJLJ_EXCEPTIONS) 381790075Sobrien sjlj_output_call_site_table (); 381890075Sobrien else 381990075Sobrien dw2_output_call_site_table (); 382090075Sobrien#endif 382190075Sobrien 382290075Sobrien /* ??? Decode and interpret the data for flag_debug_asm. */ 382390075Sobrien n = VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data); 382490075Sobrien for (i = 0; i < n; ++i) 382590075Sobrien dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->action_record_data, i), 382690075Sobrien (i ? NULL : "Action record table")); 382790075Sobrien 382890075Sobrien if (have_tt_data) 382990075Sobrien assemble_align (tt_format_size * BITS_PER_UNIT); 383090075Sobrien 383190075Sobrien i = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data); 383290075Sobrien while (i-- > 0) 383390075Sobrien { 383490075Sobrien tree type = VARRAY_TREE (cfun->eh->ttype_data, i); 383590075Sobrien rtx value; 383690075Sobrien 383790075Sobrien if (type == NULL_TREE) 383890075Sobrien type = integer_zero_node; 383990075Sobrien else 384090075Sobrien type = lookup_type_for_runtime (type); 384190075Sobrien 384290075Sobrien value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER); 384390075Sobrien if (tt_format == DW_EH_PE_absptr || tt_format == DW_EH_PE_aligned) 384490075Sobrien assemble_integer (value, tt_format_size, 384590075Sobrien tt_format_size * BITS_PER_UNIT, 1); 384690075Sobrien else 384790075Sobrien dw2_asm_output_encoded_addr_rtx (tt_format, value, NULL); 384890075Sobrien } 384990075Sobrien 385090075Sobrien#ifdef HAVE_AS_LEB128 385190075Sobrien if (have_tt_data) 385290075Sobrien ASM_OUTPUT_LABEL (asm_out_file, ttype_label); 385390075Sobrien#endif 385490075Sobrien 385590075Sobrien /* ??? Decode and interpret the data for flag_debug_asm. */ 385690075Sobrien n = VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data); 385790075Sobrien for (i = 0; i < n; ++i) 385890075Sobrien dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->ehspec_data, i), 385990075Sobrien (i ? NULL : "Exception specification table")); 386090075Sobrien 386190075Sobrien function_section (current_function_decl); 386290075Sobrien 386390075Sobrien if (USING_SJLJ_EXCEPTIONS) 386490075Sobrien sjlj_funcdef_number += 1; 386550397Sobrien} 3866