static void start_dynamic_handler PARAMS ((void));
static void expand_rethrow PARAMS ((rtx));
static void output_exception_table_entry PARAMS ((FILE *, int));
-static int can_throw PARAMS ((rtx));
static rtx scan_region PARAMS ((rtx, int, int *));
static void eh_regs PARAMS ((rtx *, rtx *, rtx *, int));
static void set_insn_eh_region PARAMS ((rtx *, int));
#ifdef DONT_USE_BUILTIN_SETJMP
static void jumpif_rtx PARAMS ((rtx, rtx));
#endif
+static void find_exception_handler_labels_1 PARAMS ((rtx));
static void mark_eh_node PARAMS ((struct eh_node *));
static void mark_eh_stack PARAMS ((struct eh_stack *));
static void mark_eh_queue PARAMS ((struct eh_queue *));
static int find_func_region_from_symbol PARAMS ((rtx));
static void clear_function_eh_region PARAMS ((void));
static void process_nestinfo PARAMS ((int, eh_nesting_info *, int *));
-
rtx expand_builtin_return_addr PARAMS ((enum built_in_function, int, rtx));
static void emit_cleanup_handler PARAMS ((struct eh_entry *));
static int eh_region_from_symbol PARAMS ((rtx));
extern struct obstack permanent_obstack;
/* Generate a SYMBOL_REF for rethrow to use */
+
static rtx
create_rethrow_ref (region_num)
int region_num;
return (*stack)->u.tlabel;
}
-/* get an exception label. These must be on the permanent obstack */
+/* Get an exception label. */
rtx
gen_exception_label ()
stack->top = node;
}
-/* push an existing entry onto a stack. */
+/* Push an existing entry onto a stack. */
+
static void
push_entry (stack, entry)
struct eh_stack *stack;
{
int range_number; /* EH region number from EH NOTE insn's. */
rtx rethrow_label; /* Label for rethrow. */
- int rethrow_ref; /* Is rethrow referenced? */
+ int rethrow_ref; /* Is rethrow_label referenced? */
+ int emitted; /* 1 if this entry has been emitted in assembly file. */
struct handler_info *handlers;
};
else
function_eh_regions[current_func_eh_entry].rethrow_label = rethrow;
function_eh_regions[current_func_eh_entry].handlers = NULL;
-
+ function_eh_regions[current_func_eh_entry].emitted = 0;
+
return current_func_eh_entry++;
}
next = ptr->next;
free (ptr);
}
- free (function_eh_regions);
+ if (function_eh_regions)
+ free (function_eh_regions);
num_func_eh_entries = 0;
current_func_eh_entry = 0;
}
/* Given a rethrow symbol, find the EH region number this is for. */
+
static int
eh_region_from_symbol (sym)
rtx sym;
/* Like find_func_region, but using the rethrow symbol for the region
rather than the region number itself. */
+
static int
find_func_region_from_symbol (sym)
rtx sym;
__rethrow as well. This performs the remap. If a symbol isn't foiund,
the original one is returned. This is not an efficient routine,
so don't call it on everything!! */
+
rtx
rethrow_symbol_map (sym, map)
rtx sym;
rtx (*map) PARAMS ((rtx));
{
int x, y;
+
+ if (! flag_new_exceptions)
+ return sym;
+
for (x = 0; x < current_func_eh_entry; x++)
if (function_eh_regions[x].rethrow_label == sym)
{
return sym;
}
+/* Returns nonzero if the rethrow label for REGION is referenced
+ somewhere (i.e. we rethrow out of REGION or some other region
+ masquerading as REGION). */
+
int
rethrow_used (region)
int region;
buf = plus_constant (XEXP (arg, 0), GET_MODE_SIZE (Pmode)*2);
#ifdef DONT_USE_BUILTIN_SETJMP
- x = emit_library_call_value (setjmp_libfunc, NULL_RTX, 1,
+ x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_CONST,
TYPE_MODE (integer_type_node), 1,
buf, Pmode);
/* If we come back here for a catch, transfer control to the handler. */
/* is the second argument 2? */
&& TREE_CODE (TREE_VALUE (args)) == INTEGER_CST
- && TREE_INT_CST_LOW (TREE_VALUE (args)) == 2
- && TREE_INT_CST_HIGH (TREE_VALUE (args)) == 0
+ && compare_tree_int (TREE_VALUE (args), 2) == 0
/* Make sure there are no other arguments. */
&& TREE_CHAIN (args) == NULL_TREE)
}
/* If we are using the setjmp/longjmp EH codegen method, we emit a
- call to __sjthrow.
-
- Otherwise, we emit a call to __throw and note that we threw
- something, so we know we need to generate the necessary code for
- __throw.
-
- Before invoking throw, the __eh_pc variable must have been set up
- to contain the PC being thrown from. This address is used by
- __throw to determine which exception region (if any) is
- responsible for handling the exception. */
+ call to __sjthrow. Otherwise, we emit a call to __throw. */
void
emit_throw ()
/* Now issue the call, and branch around handler if needed */
call_rtx = emit_library_call_value (eh_rtime_match_libfunc, NULL_RTX,
- 0, TYPE_MODE (integer_type_node),
+ LCT_NORMAL,
+ TYPE_MODE (integer_type_node),
1, rtime_address, Pmode);
/* Did the function return true? */
end_sequence ();
/* And add it to the CATCH_CLAUSES. */
- push_to_sequence (catch_clauses);
+ push_to_full_sequence (catch_clauses, catch_clauses_last);
emit_insns (handler_insns);
- catch_clauses = get_insns ();
- end_sequence ();
+ end_full_sequence (&catch_clauses, &catch_clauses_last);
/* Now we've left the handler. */
pop_ehqueue ();
pop_label_entry (&outer_context_label_stack);
/* Add the new sequence of catches to the main one for this function. */
- push_to_sequence (catch_clauses);
+ push_to_full_sequence (catch_clauses, catch_clauses_last);
emit_insns (new_catch_clause);
- catch_clauses = get_insns ();
- end_sequence ();
+ end_full_sequence (&catch_clauses, &catch_clauses_last);
/* Here we fall through into the continuation code. */
}
label = last_rethrow_symbol;
emit_library_call (rethrow_libfunc, 0, VOIDmode, 1, label, Pmode);
region = find_func_region (eh_region_from_symbol (label));
- /* If the region is -1, it doesn't exist yet. We should be
+ /* If the region is -1, it doesn't exist yet. We shouldn't be
trying to rethrow there yet. */
if (region == -1)
abort ();
}
}
eh_table[eh_table_size++] = n;
+
+ if (flag_new_exceptions)
+ {
+ /* We will output the exception table late in the compilation. That
+ references type_info objects which should have already been output
+ by that time. We explicitly mark those objects as being
+ referenced now so we know to emit them. */
+ struct handler_info *handler = get_first_handler (n);
+
+ for (; handler; handler = handler->next)
+ if (handler->type_info && handler->type_info != CATCH_ALL_TYPE)
+ {
+ tree tinfo = (tree)handler->type_info;
+
+ tinfo = TREE_OPERAND (tinfo, 0);
+ TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;
+ }
+ }
#endif
}
int index = find_func_region (n);
rtx rethrow;
- /* form and emit the rethrow label, if needed */
- rethrow = function_eh_regions[index].rethrow_label;
- if (rethrow != NULL_RTX && !flag_new_exceptions)
- rethrow = NULL_RTX;
- if (rethrow != NULL_RTX && handler == NULL)
- if (! function_eh_regions[index].rethrow_ref)
- rethrow = NULL_RTX;
+ /* Form and emit the rethrow label, if needed */
+ if (flag_new_exceptions
+ && (handler || function_eh_regions[index].rethrow_ref))
+ rethrow = function_eh_regions[index].rethrow_label;
+ else
+ rethrow = NULL_RTX;
+ if (function_eh_regions[index].emitted)
+ return;
+ function_eh_regions[index].emitted = 1;
for ( ; handler != NULL || rethrow != NULL_RTX; handler = handler->next)
{
if (rethrow != NULL_RTX && (handler == NULL || handler->next == NULL))
{
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", n);
- assemble_label(buf);
+ assemble_eh_label(buf);
rethrow = NULL_RTX;
}
ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
- assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
- assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
if (handler == NULL)
- assemble_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_eh_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1);
else
{
ASM_GENERATE_INTERNAL_LABEL (buf, "L", handler->handler_number);
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
- assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
}
if (flag_new_exceptions)
{
if (handler == NULL || handler->type_info == NULL)
- assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_eh_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
else
if (handler->type_info == CATCH_ALL_TYPE)
- assemble_integer (GEN_INT (CATCH_ALL_TYPE),
+ assemble_eh_integer (GEN_INT (CATCH_ALL_TYPE),
POINTER_SIZE / BITS_PER_UNIT, 1);
else
output_constant ((tree)(handler->type_info),
version_code = code;
}
-
+/* Free the EH table structures. */
void
-output_exception_table ()
+free_exception_table ()
+{
+ if (eh_table)
+ free (eh_table);
+ clear_function_eh_region ();
+}
+
+/* Output the common content of an exception table. */
+void
+output_exception_table_data ()
{
int i;
char buf[256];
extern FILE *asm_out_file;
- if (! doing_eh (0) || ! eh_table)
- return;
-
- exception_section ();
-
- /* Beginning marker for table. */
- assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
- assemble_label ("__EXCEPTION_TABLE__");
-
if (flag_new_exceptions)
{
- assemble_integer (GEN_INT (NEW_EH_RUNTIME),
+ assemble_eh_integer (GEN_INT (NEW_EH_RUNTIME),
POINTER_SIZE / BITS_PER_UNIT, 1);
- assemble_integer (GEN_INT (language_code), 2 , 1);
- assemble_integer (GEN_INT (version_code), 2 , 1);
+ assemble_eh_integer (GEN_INT (language_code), 2 , 1);
+ assemble_eh_integer (GEN_INT (version_code), 2 , 1);
/* Add enough padding to make sure table aligns on a pointer boundry. */
i = GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT - 4;
for ( ; i < 0; i = i + GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT)
;
if (i != 0)
- assemble_integer (const0_rtx, i , 1);
+ assemble_eh_integer (const0_rtx, i , 1);
- /* Generate the label for offset calculations on rethrows */
+ /* Generate the label for offset calculations on rethrows. */
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", 0);
- assemble_label(buf);
+ assemble_eh_label(buf);
}
for (i = 0; i < eh_table_size; ++i)
output_exception_table_entry (asm_out_file, eh_table[i]);
- free (eh_table);
- clear_function_eh_region ();
+}
+
+/* Output an exception table for the entire compilation unit. */
+void
+output_exception_table ()
+{
+ char buf[256];
+ extern FILE *asm_out_file;
+
+ if (! doing_eh (0) || ! eh_table)
+ return;
+
+ exception_section ();
+
+ /* Beginning marker for table. */
+ assemble_eh_align (GET_MODE_ALIGNMENT (ptr_mode));
+ assemble_eh_label ("__EXCEPTION_TABLE__");
+
+ output_exception_table_data ();
/* Ending marker for table. */
/* Generate the label for end of table. */
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", CODE_LABEL_NUMBER (final_rethrow));
- assemble_label(buf);
- assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_eh_label(buf);
+ assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
- /* for binary compatability, the old __throw checked the second
+ /* For binary compatibility, the old __throw checked the second
position for a -1, so we should output at least 2 -1's */
if (! flag_new_exceptions)
- assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
putc ('\n', asm_out_file); /* blank line */
}
+
+/* Used by the ia64 unwind format to output data for an individual
+ function. */
+void
+output_function_exception_table ()
+{
+ extern FILE *asm_out_file;
+
+ if (! doing_eh (0) || ! eh_table)
+ return;
+
+#ifdef HANDLER_SECTION
+ HANDLER_SECTION;
+#endif
+
+ output_exception_table_data ();
+
+ /* Ending marker for table. */
+ assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+
+ putc ('\n', asm_out_file); /* blank line */
+}
+
\f
/* Emit code to get EH context.
}
}
-/* Scan the current insns and build a list of handler labels. The
- resulting list is placed in the global variable exception_handler_labels.
+/* Scan the insn chain F and build a list of handler labels. The
+ resulting list is placed in the global variable exception_handler_labels. */
- It is called after the last exception handling region is added to
- the current function (when the rtl is almost all built for the
- current function) and before the jump optimization pass. */
-
-void
-find_exception_handler_labels ()
+static void
+find_exception_handler_labels_1 (f)
+ rtx f;
{
rtx insn;
- exception_handler_labels = NULL_RTX;
-
- /* If we aren't doing exception handling, there isn't much to check. */
- if (! doing_eh (0))
- return;
-
/* For each start of a region, add its label to the list. */
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ for (insn = f; insn; insn = NEXT_INSN (insn))
{
struct handler_info* ptr;
if (GET_CODE (insn) == NOTE
ptr->handler_label, exception_handler_labels);
}
}
+ else if (GET_CODE (insn) == CALL_INSN
+ && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
+ {
+ find_exception_handler_labels_1 (XEXP (PATTERN (insn), 0));
+ find_exception_handler_labels_1 (XEXP (PATTERN (insn), 1));
+ find_exception_handler_labels_1 (XEXP (PATTERN (insn), 2));
+ }
}
}
+/* Scan the current insns and build a list of handler labels. The
+ resulting list is placed in the global variable exception_handler_labels.
+
+ It is called after the last exception handling region is added to
+ the current function (when the rtl is almost all built for the
+ current function) and before the jump optimization pass. */
+void
+find_exception_handler_labels ()
+{
+ exception_handler_labels = NULL_RTX;
+
+ /* If we aren't doing exception handling, there isn't much to check. */
+ if (! doing_eh (0))
+ return;
+
+ find_exception_handler_labels_1 (get_insns ());
+}
+
/* Return a value of 1 if the parameter label number is an exception handler
label. Return 0 otherwise. */
mark_eh_queue (eh->x_ehqueue);
ggc_mark_rtx (eh->x_catch_clauses);
- lang_mark_false_label_stack (eh->x_false_label_stack);
+ if (lang_mark_false_label_stack)
+ (*lang_mark_false_label_stack) (eh->x_false_label_stack);
mark_tree_label_node (eh->x_caught_return_label_stack);
ggc_mark_tree (eh->x_protect_list);
}
\f
/* This section is for the exception handling specific optimization
- pass. First are the internal routines, and then the main
- optimization pass. */
+ pass. */
/* Determine if the given INSN can throw an exception. */
-static int
+int
can_throw (insn)
rtx insn;
{
+ if (GET_CODE (insn) == INSN
+ && GET_CODE (PATTERN (insn)) == SEQUENCE)
+ insn = XVECEXP (PATTERN (insn), 0, 0);
+
/* Calls can always potentially throw exceptions, unless they have
a REG_EH_REGION note with a value of 0 or less. */
if (GET_CODE (insn) == CALL_INSN)
{
rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
- if (!note || XINT (XEXP (note, 0), 0) > 0)
+ if (!note || INTVAL (XEXP (note, 0)) > 0)
return 1;
}
return 0;
}
+/* Return nonzero if nothing in this function can throw. */
+
+int
+nothrow_function_p ()
+{
+ rtx insn;
+
+ if (! flag_exceptions)
+ return 1;
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (can_throw (insn))
+ return 0;
+ for (insn = current_function_epilogue_delay_list; insn;
+ insn = XEXP (insn, 1))
+ if (can_throw (insn))
+ return 0;
+
+ return 1;
+}
+
/* Scan a exception region looking for the matching end and then
remove it if possible. INSN is the start of the region, N is the
region number, and DELETE_OUTER is to note if anything in this
/* Assume we can delete the region. */
int delete = 1;
- /* Can't delete something which is rethrown to. */
+ /* Can't delete something which is rethrown from. */
if (rethrow_used (n))
delete = 0;
}
}
-/* This function determines whether any of the exception regions in the
- current function are targets of a rethrow or not, and set the
- reference flag according. */
+/* This function determines whether the rethrow labels for any of the
+ exception regions in the current function are used or not, and set
+ the reference flag according. */
+
void
update_rethrow_references ()
{
saw_rethrow = (int *) xcalloc (current_func_eh_entry, sizeof (int));
/* Determine what regions exist, and whether there are any rethrows
- to those regions or not. */
+ from those regions or not. */
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == CALL_INSN)
{
The first passes the exception context to the handler. For this
we use the return value register for a void*.
- The second holds the stack pointer value to be restored. For
- this we use the static chain register if it exists and is different
- from the previous, otherwise some arbitrary call-clobbered register.
+ The second holds the stack pointer value to be restored. For this
+ we use the static chain register if it exists, is different from
+ the previous, and is call-clobbered; otherwise some arbitrary
+ call-clobbered register.
The third holds the address of the handler itself. Here we use
some arbitrary call-clobbered register. */
int outgoing ATTRIBUTE_UNUSED;
{
rtx rcontext, rsp, rra;
- int i;
+ unsigned int i;
#ifdef FUNCTION_OUTGOING_VALUE
if (outgoing)
rsp = static_chain_incoming_rtx;
else
rsp = static_chain_rtx;
- if (REGNO (rsp) == REGNO (rcontext))
+ if (REGNO (rsp) == REGNO (rcontext)
+ || ! call_used_regs [REGNO (rsp)])
#endif /* STATIC_CHAIN_REGNUM */
rsp = NULL_RTX;
yet. At some point in the future we can trim out handlers which we
know cannot be called. (ie, if a block has an INT type handler,
control will never be passed to an outer INT type handler). */
+
static void
process_nestinfo (block, info, nested_eh_region)
int block;
/* This function will allocate and initialize an eh_nesting_info structure.
It returns a pointer to the completed data structure. If there are
no exception regions, a NULL value is returned. */
+
eh_nesting_info *
init_eh_nesting_info ()
{
rtx insn;
int x;
+ if (! flag_exceptions)
+ return 0;
+
info = (eh_nesting_info *) xmalloc (sizeof (eh_nesting_info));
info->region_index = (int *) xcalloc ((max_label_num () + 1), sizeof (int));
nested_eh_region = (int *) xcalloc (max_label_num () + 1, sizeof (int));
HANDLERS is the address of a pointer to a vector of handler_info pointers.
Upon return, this will have the handlers which can be reached by block.
This function returns the number of elements in the handlers vector. */
+
int
reachable_handlers (block, info, insn, handlers)
int block;
if (insn && GET_CODE (insn) == CALL_INSN)
{
/* RETHROWs specify a region number from which we are going to rethrow.
- This means we wont pass control to handlers in the specified
+ This means we won't pass control to handlers in the specified
region, but rather any region OUTSIDE the specified region.
We accomplish this by setting block to the outer_index of the
specified region. */
note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
if (note)
{
- int b = XINT (XEXP (note, 0), 0);
+ int b = INTVAL (XEXP (note, 0));
if (b <= 0)
index = 0;
else