Commit ce152ef8 by Andrew MacLeod Committed by Andrew Haley

except.c (func_eh_entry): Add emitted field.

2000-05-25  Andrew MacLeod  <amacleod@cygnus.com>
            Andrew Haley  <aph@cygnus.com>

	* except.c  (func_eh_entry): Add emitted field.
	(new_eh_region_entry): Set emitted field to 0;
	(output_exception_table_entry): Only emit previously un-emitted data,
	and send it to the eh_data section.
	(output_exception_table): Break out common parts. Output
	exception table for entire compilation unit to eh_data section.
	(output_exception_table_data): Common parts of output_exception_table.
	Send output to eh_data section.
	(output_function_exception_table): Output exception table data for
	a single function to eh_data section.
	(free_exception_table): New external to free the table.
	* except.h (free_exception_table): Add prototype.
	(output_function_exception_table): Add prototype.
	* final.c (final_end_function): Output function exception table
	for IA64_UNWIND_INFO.
	(final_scan_insn): Emit any unwind directives for an insn.

	* frame-dwarf2.c: New file containing all DWARF 2 specific code
	from frame.c.
	* frame.c: Remove all DWARF 2 specific code.
	* config/ia64/frame-ia64.c: New file.
	(gthread_stuff): Make all gthread available with
	IA64_UNWIND_INFO.
	(dwarf_fde): Define an IA64 struct for dwarf_fde.
	(__register_frame_info, __register_frame): Move to common area of file.
	(__register_frame_info_table, __register_frame_table): Move to common i
	area.
	(__deregister_frame_info, __deregister_frame): Move to common area.
	(__frame_init, find_fde): New versions for IA64_UNWIND_INFO.
	(read_uleb128): New version for ia64.
	(get_unwind_record): Read the next IA-64 unwind record.
	(read_R_record): Read a region header record.
	(process_a_b_reg_code): X record helper.
	(read_X_record): Read an X format record.
	(read_B_record): Read a B format record.
	(P3_record_types): List of record types matching the P3 format.
	(P7_record_types): List of record types matching the P7 format.
	(P8_record_types): List of record types matching the P8 format.
	(read_P_record): Read a P format record.
	(init_ia64_reg_loc): Set default fields for a register.
	(init_ia64_unwind_frame): Set defaults for all register records.
	(execute_one_ia64_descriptor): Execute one descriptor record.
	(rse_address_add): Calculate the position of a local reg in memory.
	(normalize_reg_loc): Turn a location descriptor into a memory address.
	(maybe_normalize_reg_loc): Only normalize a descriptor if it falls
	within a specified PC offset range.
	(get_real_reg_value): Given a register location, retrieve its value.
	(set_real_reg_value): Change the value of a register location.
	(copy_reg_value): Copy reg values, if needed.
	(copy_saved_reg_state): Copy all registers that need to be copied.
	(process_state_between): Normalize all frame register records that
	fall within the specified PC range.
	(frame_translate): Take a processed frame description, and turn
	everything into addresses.
	(build_ia64_frame_state ): Find and create frame state record for a PC.
	(get_personality): Get the personality routine for a given frame.
	(get_except_table): Get the exception table for a given frame.
	(record_name): Unwind record names for debugging.
	(print_record): Print and unwind record.
	(print_all_records): Print an entire unwind image.
	(__ia64_backtrace): Print a backtrace.
	(ia64_backtrace_helper): New function.
	(__register_frame_info_aux): New function.
	* config/ia64/crtend.asm (__do_frame_setup_aux): New function.

	* frame.h (enum unw_record_type): New unwind record types.
	(struct unw_p_record, unw_b_record, unw_x_record) : New unwind records.
	(struct unw_r_record, unwind_record): New unwind record structs.
	(struct unwind_info_ptr): Unwind information layout.
	(IA64_UNW_LOC_TYPE_*): Macros for different types for location
	descriptors.
	(struct ia64_reg_loc): Register location description.
	(struct ia64_frame_state): Location of all registers in a frame.
	(struct object): Add pc_base and fde_end for IA64_UNWIND_INFO.
	* libgcc2.c (__ia64_personality_v1): Personality routine.
	(__calc_caller_bsp): Calculate the bsp register for the caller's
	frame.
	(ia64_throw_helper): Figure out who to return to and set up the
	registers.
	(__throw): Throw routine.

	* output.h (assemble_eh_align, assemble_eh_label): New functions
	to generate EH info where we want it.
	(assemble_eh_integer): New function.
	* toplev.c (compile_file): Output module level exception table for
	non-ia64 targets.
	(main): Set exceptions_via_longjump and flag_new_exceptions based
	on IA64_UNWIND_INFO too.

	* varasm.c (assemble_eh_label): Generate a label via
	ASM_OUTPUT_EH_LABEL if it has been specified.
	(assemble_eh_align): Generate an alignment directive via
	ASM_OUTPUT_EH_ALIGN if it has been specified.
	(assemble_eh_label): Generate an integer value via
	ASM_OUTPUT_EH_type if they have been specified.
	* config/ia64/ia64.c (rtx_needs_barrier): Add flushrs.
	(ia64_init_builtins): Add __builtin_ia64_bsp
	and __builtin_ia64_flushrs.
	(ia64_expand_builtin): Add IA64_BUILTIN_BSP and
	IA64_BUILTIN_FLUSHRS.
	* config/ia64/ia64.h (ia64_builtins): Add IA64_BUILTIN_BSP and
	IA64_BUILTIN_FLUSHRS.

	* config/ia64/ia64.md (flushrs): New insn to flush the register
	stack.  Add to unspec list.

	* config/ia64/crtbegin.asm (frame_object): Change size.
	(__do_frame_setup_aux): New function.
	* config/ia64/crtend.asm: call __do_frame_setup_aux.
	* config/ia64/t-ia64 (LIB2ADDEH): Add.
	* Makefile.in (LIB2ADDEH): Add.
	(LIB2ADD): Use LIB2ADDEH.

Co-Authored-By: Andrew Haley <aph@cygnus.com>

From-SVN: r34169
parent c66265e4
2000-05-25 Andrew MacLeod <amacleod@cygnus.com>
Andrew Haley <aph@cygnus.com>
* except.c (func_eh_entry): Add emitted field.
(new_eh_region_entry): Set emitted field to 0;
(output_exception_table_entry): Only emit previously un-emitted data,
and send it to the eh_data section.
(output_exception_table): Break out common parts. Output
exception table for entire compilation unit to eh_data section.
(output_exception_table_data): Common parts of output_exception_table.
Send output to eh_data section.
(output_function_exception_table): Output exception table data for
a single function to eh_data section.
(free_exception_table): New external to free the table.
* except.h (free_exception_table): Add prototype.
(output_function_exception_table): Add prototype.
* final.c (final_end_function): Output function exception table
for IA64_UNWIND_INFO.
(final_scan_insn): Emit any unwind directives for an insn.
* frame-dwarf2.c: New file containing all DWARF 2 specific code
from frame.c.
* frame.c: Remove all DWARF 2 specific code.
* config/ia64/frame-ia64.c: New file.
(gthread_stuff): Make all gthread available with
IA64_UNWIND_INFO.
(dwarf_fde): Define an IA64 struct for dwarf_fde.
(__register_frame_info, __register_frame): Move to common area of file.
(__register_frame_info_table, __register_frame_table): Move to common i
area.
(__deregister_frame_info, __deregister_frame): Move to common area.
(__frame_init, find_fde): New versions for IA64_UNWIND_INFO.
(read_uleb128): New version for ia64.
(get_unwind_record): Read the next IA-64 unwind record.
(read_R_record): Read a region header record.
(process_a_b_reg_code): X record helper.
(read_X_record): Read an X format record.
(read_B_record): Read a B format record.
(P3_record_types): List of record types matching the P3 format.
(P7_record_types): List of record types matching the P7 format.
(P8_record_types): List of record types matching the P8 format.
(read_P_record): Read a P format record.
(init_ia64_reg_loc): Set default fields for a register.
(init_ia64_unwind_frame): Set defaults for all register records.
(execute_one_ia64_descriptor): Execute one descriptor record.
(rse_address_add): Calculate the position of a local reg in memory.
(normalize_reg_loc): Turn a location descriptor into a memory address.
(maybe_normalize_reg_loc): Only normalize a descriptor if it falls
within a specified PC offset range.
(get_real_reg_value): Given a register location, retrieve its value.
(set_real_reg_value): Change the value of a register location.
(copy_reg_value): Copy reg values, if needed.
(copy_saved_reg_state): Copy all registers that need to be copied.
(process_state_between): Normalize all frame register records that
fall within the specified PC range.
(frame_translate): Take a processed frame description, and turn
everything into addresses.
(build_ia64_frame_state ): Find and create frame state record for a PC.
(get_personality): Get the personality routine for a given frame.
(get_except_table): Get the exception table for a given frame.
(record_name): Unwind record names for debugging.
(print_record): Print and unwind record.
(print_all_records): Print an entire unwind image.
(__ia64_backtrace): Print a backtrace.
(ia64_backtrace_helper): New function.
(__register_frame_info_aux): New function.
* config/ia64/crtend.asm (__do_frame_setup_aux): New function.
* frame.h (enum unw_record_type): New unwind record types.
(struct unw_p_record, unw_b_record, unw_x_record) : New unwind records.
(struct unw_r_record, unwind_record): New unwind record structs.
(struct unwind_info_ptr): Unwind information layout.
(IA64_UNW_LOC_TYPE_*): Macros for different types for location
descriptors.
(struct ia64_reg_loc): Register location description.
(struct ia64_frame_state): Location of all registers in a frame.
(struct object): Add pc_base and fde_end for IA64_UNWIND_INFO.
* libgcc2.c (__ia64_personality_v1): Personality routine.
(__calc_caller_bsp): Calculate the bsp register for the caller's
frame.
(ia64_throw_helper): Figure out who to return to and set up the
registers.
(__throw): Throw routine.
* output.h (assemble_eh_align, assemble_eh_label): New functions
to generate EH info where we want it.
(assemble_eh_integer): New function.
* toplev.c (compile_file): Output module level exception table for
non-ia64 targets.
(main): Set exceptions_via_longjump and flag_new_exceptions based
on IA64_UNWIND_INFO too.
* varasm.c (assemble_eh_label): Generate a label via
ASM_OUTPUT_EH_LABEL if it has been specified.
(assemble_eh_align): Generate an alignment directive via
ASM_OUTPUT_EH_ALIGN if it has been specified.
(assemble_eh_label): Generate an integer value via
ASM_OUTPUT_EH_type if they have been specified.
* config/ia64/ia64.c (rtx_needs_barrier): Add flushrs.
(ia64_init_builtins): Add __builtin_ia64_bsp
and __builtin_ia64_flushrs.
(ia64_expand_builtin): Add IA64_BUILTIN_BSP and
IA64_BUILTIN_FLUSHRS.
* config/ia64/ia64.h (ia64_builtins): Add IA64_BUILTIN_BSP and
IA64_BUILTIN_FLUSHRS.
* config/ia64/ia64.md (flushrs): New insn to flush the register
stack. Add to unspec list.
* config/ia64/crtbegin.asm (frame_object): Change size.
(__do_frame_setup_aux): New function.
* config/ia64/crtend.asm: call __do_frame_setup_aux.
* config/ia64/t-ia64 (LIB2ADDEH): Add.
* Makefile.in (LIB2ADDEH): Add.
(LIB2ADD): Use LIB2ADDEH.
2000-05-24 Richard Henderson <rth@cygnus.com>
* recog.c (offsettable_address_p): If mode size is zero, assume
......@@ -367,6 +367,9 @@ LIBGCC2_INCLUDES =
# Additional target-dependent options for compiling libgcc2.a.
TARGET_LIBGCC2_CFLAGS =
# Addition sources to handle exceptions; overridden by some targets.
LIB2ADDEH = $(srcdir)/frame-dwarf2.c
# libgcc1-test target (must also be overridable for a target)
LIBGCC1_TEST = libgcc1-test
......@@ -951,7 +954,7 @@ libgcc2.ready: $(GCC_PASSES) stmp-int-hdrs $(STMP_FIXPROTO)
touch libgcc2.ready; \
fi
LIB2ADD = $(srcdir)/frame.c $(LIB2FUNCS_EXTRA) $(LANG_LIB2FUNCS)
LIB2ADD = $(LIB2ADDEH) $(LIB2FUNCS_EXTRA) $(LANG_LIB2FUNCS)
libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) xgcc$(exeext)
objext='$(objext)' \
......
......@@ -61,10 +61,10 @@ __dso_handle:
/* ??? How can we rationally keep this size correct? */
.section .bss
.type frame_object#,@object
.size frame_object#,56
.size frame_object#,64
.align 8
frame_object:
.zero 56
.zero 64
/*
* Fragment of the ELF _fini routine that invokes our dtor cleanup.
......@@ -296,3 +296,38 @@ __do_frame_setup:
#endif
.weak __deregister_frame_info#
.weak __register_frame_info#
.text
.align 16
.global __do_frame_setup_aux#
.proc __do_frame_setup_aux#
__do_frame_setup_aux:
/*
if (__register_frame_info_aux)
__register_frame_info_aux(__EH_FRAME_END__)
*/
alloc loc0 = ar.pfs, 0, 3, 1, 0
addl r14 = @ltoff(@fptr(__register_frame_info_aux#)), gp
mov loc1 = b0
;;
// r16 contains the address of a pointer to __EH_FRAME_END__.
ld8 out0 = [r16]
ld8 r15 = [r14]
mov loc2 = gp
;;
cmp.eq p6, p7 = 0, r15
(p6) br.cond.dptk 1f
ld8 r8 = [r15], 8
;;
ld8 gp = [r15]
mov b6 = r8
;;
br.call.sptk.many b0 = b6
;;
1:
mov gp = loc2
mov ar.pfs = loc0
mov b0 = loc1
br.ret.sptk.many b0
.endp __do_frame_setup#
.weak __register_frame_info_aux#
......@@ -110,3 +110,25 @@ __do_global_ctors_aux:
;;
}
.endp __do_global_ctors_aux#
.section .init,"ax","progbits"
{ .mlx
// __do_frame_setup_aux is in crtbegin.asm
movl r2 = @gprel(__do_frame_setup_aux#)
;;
}
{ .mii
nop.m 0
add r2 = r2, gp
;;
mov b6 = r2
}
{ .mib
// __do_frame_setup_aux needs the address of __EH_FRAME_END__,
// so we pass it in r16. This is rather evil, but we have no
// output registers.
addl r16 = @ltoff(__EH_FRAME_END__#), gp
br.call.sptk.many b0 = b6
;;
}
......@@ -2606,6 +2606,8 @@ rtx_needs_barrier (x, flags, pred)
break;
case 20: /* mov = ar.bsp */
break;
case 21: /* flushrs */
break;
default:
abort ();
......@@ -3329,6 +3331,12 @@ ia64_init_builtins ()
def_builtin ("__sync_lock_release_di", void_ftype_pdi, IA64_BUILTIN_LOCK_RELEASE_DI);
def_builtin ("__builtin_ia64_bsp", build_function_type (ptr_type_node, endlink), IA64_BUILTIN_BSP);
def_builtin ("__builtin_ia64_flushrs",
build_function_type (void_type_node, endlink),
IA64_BUILTIN_FLUSHRS);
/* Add all builtins that are operations on two args. */
for (i=0, d = bdesc_2argsi; i < sizeof(bdesc_2argsi) / sizeof *d; i++, d++)
def_builtin (d->name, si_ftype_psi_si, d->code);
......@@ -3743,6 +3751,19 @@ ia64_expand_builtin (exp, target, subtarget, mode, ignore)
emit_insn (gen_movdi (op0, GEN_INT(0)));
return 0;
case IA64_BUILTIN_BSP:
{
rtx reg = gen_reg_rtx (DImode);
emit_insn (gen_bsp_value (reg));
return reg;
}
case IA64_BUILTIN_FLUSHRS:
{
emit_insn (gen_flushrs ());
return 0;
}
default:
break;
}
......
......@@ -2893,7 +2893,10 @@ enum ia64_builtins
IA64_BUILTIN_LOCK_TEST_AND_SET_DI,
IA64_BUILTIN_LOCK_RELEASE_DI
IA64_BUILTIN_LOCK_RELEASE_DI,
IA64_BUILTIN_BSP,
IA64_BUILTIN_FLUSHRS
};
/* Codes for expand_compare_and_swap and expand_swap_and_compare. */
......
......@@ -48,6 +48,10 @@
;; ??? Add function unit scheduling info for Itanium (TM) processor.
;; ??? The explicit stop in the flushrs pattern is not ideal. It
;; would be better if rtx_needs_barrier took care of this, but this is
;; something that can be fixed later.
;; Unspec usage:
;;
;; unspec:
......@@ -66,6 +70,7 @@
;; 18 fetch_and_op
;; 19 fetchadd_acq
;; 20 bsp_value
;; 21 flushrs
;;
;; unspec_volatile:
;; 0 alloc
......@@ -3243,6 +3248,12 @@
mov ar.rsc=r19\;"
[(set_attr "type" "unknown")
(set_attr "predicable" "no")])
(define_insn "flushrs"
[(unspec [(const_int 0)] 21)]
""
";; \; flushrs"
[(set_attr "type" "M")])
;; ::::::::::::::::::::
;; ::
......
......@@ -39,3 +39,5 @@ crtendS.o: $(srcdir)/config/ia64/crtend.asm $(GCC_PASSES)
$(GCC_FOR_TARGET) -DSHARED -c -o crtendS.o -x assembler-with-cpp $(srcdir)/config/ia64/crtend.asm
EXTRA_HEADERS = $(srcdir)/config/ia64/ia64intrin.h
LIB2ADDEH = $(srcdir)/config/ia64/frame-ia64.c
......@@ -698,6 +698,7 @@ struct func_eh_entry
int range_number; /* EH region number from EH NOTE insn's. */
rtx rethrow_label; /* Label for rethrow. */
int rethrow_ref; /* Is rethrow_label referenced? */
int emitted; /* 1 if this entry has been emitted in assembly file. */
struct handler_info *handlers;
};
......@@ -739,7 +740,8 @@ new_eh_region_entry (note_eh_region, rethrow)
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++;
}
......@@ -2221,40 +2223,44 @@ output_exception_table_entry (file, n)
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)
{
/* rethrow label should indicate the LAST entry for a region */
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),
......@@ -2288,61 +2294,100 @@ set_exception_version_code (code)
version_code = code;
}
/* Free the EH table structures. */
void
output_exception_table ()
free_exception_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. */
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 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 */
}
/* Emit code to get EH context.
......
......@@ -355,6 +355,15 @@ extern int exception_table_p PARAMS ((void));
extern void output_exception_table PARAMS ((void));
/* Free the exception table. */
extern void free_exception_table PARAMS((void));
/* Used by the ia64 unwind format to output data for an individual
function. */
extern void output_function_exception_table PARAMS((void));
/* Given a return address in ADDR, determine the address we should use
to find the corresponding EH region. */
......
......@@ -1827,6 +1827,10 @@ final_end_function (first, file, optimize)
bb_func_label_num = -1; /* not in function, nuke label # */
#ifdef IA64_UNWIND_INFO
output_function_exception_table ();
#endif
/* If FUNCTION_EPILOGUE is not defined, then the function body
itself contains return instructions wherever needed. */
}
......@@ -2968,6 +2972,9 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
if (prescan > 0)
break;
#ifdef IA64_UNWIND_INFO
IA64_UNWIND_EMIT (asm_out_file, insn);
#endif
/* Output assembler code from the template. */
output_asm_insn (template, recog_data.operand);
......
......@@ -50,9 +50,15 @@ typedef struct frame_state
keep the copies synchronized! */
struct object {
#ifdef IA64_UNWIND_INFO
void *pc_base; /* This field will be set by find_fde. */
#endif
void *pc_begin;
void *pc_end;
struct dwarf_fde *fde_begin;
#ifdef IA64_UNWIND_INFO
struct dwarf_fde *fde_end;
#endif
struct dwarf_fde **fde_array;
size_t count;
struct object *next;
......@@ -87,3 +93,184 @@ extern void *__deregister_frame_info (void *);
Returns NULL on failure, otherwise returns STATE_IN. */
extern struct frame_state *__frame_state_for (void *, struct frame_state *);
#ifdef IA64_UNWIND_INFO
/* This is the information required for unwind records in an ia64
object file. This is required by GAS and the compiler runtime. */
/* These are the starting point masks for the various types of
unwind records. To create a record of type R3 for instance, one
starts by using the value UNW_R3 and or-ing in any other required values.
These values are also unique (in context), so they can be used to identify
the various record types as well. UNW_Bx and some UNW_Px do have the
same value, but Px can only occur in a prologue context, and Bx in
a body context. */
#define UNW_R1 0x00
#define UNW_R2 0x40
#define UNW_R3 0x60
#define UNW_P1 0x80
#define UNW_P2 0xA0
#define UNW_P3 0xB0
#define UNW_P4 0xB8
#define UNW_P5 0xB9
#define UNW_P6 0xC0
#define UNW_P7 0xE0
#define UNW_P8 0xF0
#define UNW_P9 0xF1
#define UNW_P10 0xFF
#define UNW_X1 0xF9
#define UNW_X2 0xFA
#define UNW_X3 0xFB
#define UNW_X4 0xFC
#define UNW_B1 0x80
#define UNW_B2 0xC0
#define UNW_B3 0xE0
#define UNW_B4 0xF0
/* These are all the various types of unwind records. */
typedef enum
{
prologue, prologue_gr, body, mem_stack_f, mem_stack_v, psp_gr, psp_sprel,
rp_when, rp_gr, rp_br, rp_psprel, rp_sprel, pfs_when, pfs_gr, pfs_psprel,
pfs_sprel, preds_when, preds_gr, preds_psprel, preds_sprel,
fr_mem, frgr_mem, gr_gr, gr_mem, br_mem, br_gr, spill_base, spill_mask,
unat_when, unat_gr, unat_psprel, unat_sprel, lc_when, lc_gr, lc_psprel,
lc_sprel, fpsr_when, fpsr_gr, fpsr_psprel, fpsr_sprel,
priunat_when_gr, priunat_when_mem, priunat_gr, priunat_psprel,
priunat_sprel, bsp_when, bsp_gr, bsp_psprel, bsp_sprel, bspstore_when,
bspstore_gr, bspstore_psprel, bspstore_sprel, rnat_when, rnat_gr,
rnat_psprel, rnat_sprel, epilogue, label_state, copy_state,
spill_psprel, spill_sprel, spill_reg, spill_psprel_p, spill_sprel_p,
spill_reg_p
} unw_record_type;
/* These structures declare the fields that can be used in each of the
4 record formats, R, P, B and X. */
typedef struct unw_r_record
{
unsigned long rlen;
unsigned short mask;
unsigned short grsave;
} unw_r_record;
typedef struct unw_p_record
{
void *imask;
unsigned long t;
unsigned long size;
unsigned long spoff;
unsigned long br;
unsigned long pspoff;
unsigned short gr;
unsigned short rmask;
unsigned short grmask;
unsigned long frmask;
unsigned short brmask;
} unw_p_record;
typedef struct unw_b_record
{
unsigned long t;
unsigned long label;
unsigned short ecount;
} unw_b_record;
typedef struct unw_x_record
{
unsigned long t;
unsigned long spoff;
unsigned long pspoff;
unsigned short reg;
unsigned short treg;
unsigned short qp;
unsigned short xy; /* Value of the XY field.. */
} unw_x_record;
/* This structure is used to determine the specific record type and
its fields. */
typedef struct unwind_record
{
unw_record_type type;
union {
unw_r_record r;
unw_p_record p;
unw_b_record b;
unw_x_record x;
} record;
} unwind_record;
#define IA64_UNW_LOC_TYPE_NONE 0
#define IA64_UNW_LOC_TYPE_MEM 1
#define IA64_UNW_LOC_TYPE_GR 2
#define IA64_UNW_LOC_TYPE_FR 3
#define IA64_UNW_LOC_TYPE_BR 4
#define IA64_UNW_LOC_TYPE_SPOFF 5
#define IA64_UNW_LOC_TYPE_PSPOFF 6
#define IA64_UNW_LOC_TYPE_OFFSET 7
#define IA64_UNW_LOC_TYPE_SPILLBASE 8
typedef struct ia64_reg_loc
{
long when; /* PC relative offset from start of function. */
union { /* In memory or another register? */
void *mem;
int regno;
int offset;
} l;
short loc_type; /* Where to find value. */
short reg_size;
} ia64_reg_loc;
/* Frame information record. */
typedef struct ia64_frame_state
{
ia64_reg_loc gr[4]; /* gr4 to gr7. */
ia64_reg_loc fr[20]; /* fr2 to fr5, fr16 to fr31. */
ia64_reg_loc br[5]; /* br1 to br5. */
ia64_reg_loc rp;
ia64_reg_loc fpsr;
ia64_reg_loc bsp;
ia64_reg_loc bspstore;
ia64_reg_loc rnat;
ia64_reg_loc pfs;
ia64_reg_loc unat;
ia64_reg_loc lc;
ia64_reg_loc pr;
ia64_reg_loc priunat;
ia64_reg_loc sp;
ia64_reg_loc psp;
ia64_reg_loc spill_base;
void *my_sp;
void *my_bsp;
} ia64_frame_state;
/* This structure represents the start of an unwind information pointer.
'unwind_descriptors' is the beginninng of the unwind descriptors, which
use up 'length' bytes of storage. */
typedef struct unwind_info_ptr
{
unsigned short version;
unsigned short flags;
unsigned int length;
unsigned char unwind_descriptors[1];
} unwind_info_ptr;
extern unwind_info_ptr *__build_ia64_frame_state (unsigned char *,
ia64_frame_state *, void *,
void **);
extern void *__get_real_reg_value (ia64_reg_loc *);
extern void *__get_personality (unwind_info_ptr *);
extern void *__get_except_table (unwind_info_ptr *);
extern void __set_real_reg_value (ia64_reg_loc *, void *);
void *__calc_caller_bsp (long, unsigned char *);
void __copy_saved_reg_state (ia64_frame_state *, ia64_frame_state *);
#endif /* IA64_UNWIND_INFO */
......@@ -3940,6 +3940,173 @@ label:
}
#endif /* DWARF2_UNWIND_INFO */
#ifdef IA64_UNWIND_INFO
#include "frame.h"
/* Return handler to which we want to transfer control, NULL if we don't
intend to handle this exception here. */
void *
__ia64_personality_v1 (void *pc, old_exception_table *table)
{
if (table)
{
int pos;
int best = -1;
for (pos = 0; table[pos].start_region != (void *) -1; ++pos)
{
if (table[pos].start_region <= pc && table[pos].end_region > pc)
{
/* This can apply. Make sure it is at least as small as
the previous best. */
if (best == -1 || (table[pos].end_region <= table[best].end_region
&& table[pos].start_region >= table[best].start_region))
best = pos;
}
/* It is sorted by starting PC within a function. */
else if (best >= 0 && table[pos].start_region > pc)
break;
}
if (best != -1)
return table[best].exception_handler;
}
return (void *) 0;
}
static void
ia64_throw_helper (throw_pc, throw_frame, caller, throw_bsp)
void *throw_pc;
ia64_frame_state *throw_frame;
ia64_frame_state *caller;
void *throw_bsp;
{
unwind_info_ptr *info;
void *pc, *handler = NULL;
void *pc_base;
int frame_count;
void *bsp;
__builtin_ia64_flushrs (); /* Make the local register stacks available. */
/* Start at our stack frame, get our state. */
__build_ia64_frame_state (throw_pc, throw_frame, throw_bsp, &pc_base);
/* Now we have to find the proper frame for pc, and see if there
is a handler for it. if not, we keep going back frames until
we do find one. Otherwise we call uncaught (). */
frame_count = 0;
memcpy (caller, throw_frame, sizeof (*caller));
while (!handler)
{
void *(*personality) ();
void *eh_table;
frame_count++;
/* We only care about the RP right now, so we dont need to keep
any other information about a call frame right now. */
pc = __get_real_reg_value (&caller->rp) - 1;
bsp = __calc_caller_bsp ((long)__get_real_reg_value (&caller->pfs), caller->my_bsp);
info = __build_ia64_frame_state (pc, caller, bsp, &pc_base);
/* If we couldn't find the next frame, we lose. */
if (! info)
break;
personality = __get_personality (info);
/* TODO Haven't figured out how to actually load the personality address
yet, so just always default to the one we expect for now. */
if (personality != 0)
personality = __ia64_personality_v1;
eh_table = __get_except_table (info);
/* If there is no personality routine, we'll keep unwinding. */
if (personality)
/* Pass a segment relative PC address to the personality routine,
because the unwind_info section uses segrel relocs. */
handler = personality (pc - pc_base, eh_table);
}
if (!handler)
__terminate ();
/* Handler is a segment relative address, so we must adjust it here. */
handler += (long) pc_base;
/* If we found a handler, we need to unwind the stack to that point.
We do this by copying saved values from previous frames into the
save slot for the throw_frame saved slots. when __throw returns,
it'll pickup the correct values. */
/* Start with where __throw saved things, and copy each saved register
of each previous frame until we get to the one before we're
throwing back to. */
memcpy (caller, throw_frame, sizeof (*caller));
for ( ; frame_count > 0; frame_count--)
{
pc = __get_real_reg_value (&caller->rp) - 1;
bsp = __calc_caller_bsp ((long)__get_real_reg_value (&caller->pfs), caller->my_bsp);
__build_ia64_frame_state (pc, caller, bsp, &pc_base);
/* Any regs that were saved can be put in the throw frame now. */
/* We don't want to copy any saved register from the
target destination, but we do want to load up it's frame. */
if (frame_count > 1)
__copy_saved_reg_state (throw_frame, caller);
}
/* Set return address of the throw frame to the handler. */
__set_real_reg_value (&throw_frame->rp, handler);
/* TODO, do we need to do anything to make the values we wrote 'stick'? */
/* DO we need to go through the whole loadrs seqeunce? */
}
void
__throw ()
{
struct eh_context *eh = (*get_eh_context) ();
ia64_frame_state my_frame;
ia64_frame_state originator; /* For the context handler is in. */
void *bsp, *tmp_bsp;
long offset;
/* This is required for C++ semantics. We must call terminate if we
try and rethrow an exception, when there is no exception currently
active. */
if (! eh->info)
__terminate ();
__builtin_unwind_init ();
label_ia64:
/* We have to call another routine to actually process the frame
information, which will force all of __throw's local registers into
backing store. */
/* Get the value of ar.bsp while we're here. */
bsp = __builtin_ia64_bsp ();
ia64_throw_helper (&&label_ia64, &my_frame, &originator, bsp);
/* Now we have to fudge the bsp by the amount in our (__throw)
frame marker, since the return is going to adjust it by that much. */
tmp_bsp = __calc_caller_bsp ((long)__get_real_reg_value (&my_frame.pfs),
my_frame.my_bsp);
offset = (char *)my_frame.my_bsp - (char *)tmp_bsp;
tmp_bsp = (char *)originator.my_bsp + offset;
/* A throw handler is trated like a non-local goto, which is architeched
to set the FP (or PSP) in r7 before branching. gr[0-3] map to
r4-r7, so we want gr[3]. */
__set_real_reg_value (&my_frame.gr[3], __get_real_reg_value (&originator.psp));
__builtin_eh_return (tmp_bsp, offset, originator.my_sp);
/* The return address was already set by throw_helper. */
}
#endif /* IA64_UNWIND_INFO */
#endif /* L_eh */
#ifdef L_pure
......
......@@ -292,6 +292,7 @@ extern void assemble_zeros PARAMS ((int));
/* Assemble an alignment pseudo op for an ALIGN-bit boundary. */
extern void assemble_align PARAMS ((int));
extern void assemble_eh_align PARAMS ((int));
/* Assemble a string constant with the specified C string as contents. */
extern void assemble_string PARAMS ((const char *, int));
......@@ -306,6 +307,7 @@ extern void assemble_global PARAMS ((const char *));
/* Assemble a label named NAME. */
extern void assemble_label PARAMS ((const char *));
extern void assemble_eh_label PARAMS ((const char *));
/* Output to FILE a reference to the assembler name of a C-level name NAME.
If NAME starts with a *, the rest of NAME is output verbatim.
......@@ -321,6 +323,7 @@ extern void assemble_name PARAMS ((FILE *, const char *));
Return 1 if we were able to output the constant, otherwise 0. If FORCE is
non-zero, abort if we can't output the constant. */
extern int assemble_integer PARAMS ((rtx, int, int));
extern int assemble_eh_integer PARAMS ((rtx, int, int));
#ifdef EMUSHORT
/* Assemble the floating-point constant D into an object of size MODE. */
......
......@@ -2336,8 +2336,11 @@ compile_file (name)
/* Now that all possible functions have been output, we can dump
the exception table. */
#ifndef IA64_UNWIND_INFO
output_exception_table ();
#endif
free_exception_table ();
check_global_declarations (vec, len);
/* Clean up. */
......@@ -4605,10 +4608,22 @@ main (argc, argv)
#ifdef DWARF2_UNWIND_INFO
exceptions_via_longjmp = ! DWARF2_UNWIND_INFO;
#else
#ifdef IA64_UNWIND_INFO
exceptions_via_longjmp = ! IA64_UNWIND_INFO;
#else
exceptions_via_longjmp = 1;
#endif
#endif
}
/* Since each function gets its own handler data, we can't support the
new model currently, since it depend on a specific rethrow label
which is declared at the front of the table, and we can only
have one such symbol in a file. */
#ifdef IA64_UNWIND_INFO
flag_new_exceptions = 0;
#endif
/* Set up the align_*_log variables, defaulting them to 1 if they
were still unset. */
if (align_loops <= 0) align_loops = 1;
......
......@@ -4836,3 +4836,74 @@ init_varasm_once ()
mark_const_hash_entry);
ggc_add_string_root (&in_named_name, 1);
}
/* Extra support for EH values. */
void
assemble_eh_label (name)
const char *name;
{
#ifdef ASM_OUTPUT_EH_LABEL
ASM_OUTPUT_EH_LABEL (asm_out_file, name);
#else
assemble_label (name);
#endif
}
/* Assemble an alignment pseudo op for an ALIGN-bit boundary. */
void
assemble_eh_align (align)
int align;
{
#ifdef ASM_OUTPUT_EH_ALIGN
if (align > BITS_PER_UNIT)
ASM_OUTPUT_EH_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
#else
assemble_align (align);
#endif
}
/* On some platforms, we may want to specify a special mechansim to
output EH data when generating with a function.. */
int
assemble_eh_integer (x, size, force)
rtx x;
int size;
int force;
{
switch (size)
{
#ifdef ASM_OUTPUT_EH_CHAR
case 1:
ASM_OUTPUT_EH_CHAR (asm_out_file, x);
return 1;
#endif
#ifdef ASM_OUTPUT_EH_SHORT
case 2:
ASM_OUTPUT_EH_SHORT (asm_out_file, x);
return 1;
#endif
#ifdef ASM_OUTPUT_EH_INT
case 4:
ASM_OUTPUT_EH_INT (asm_out_file, x);
return 1;
#endif
#ifdef ASM_OUTPUT_EH_DOUBLE_INT
case 8:
ASM_OUTPUT_EH_DOUBLE_INT (asm_out_file, x);
return 1;
#endif
default:
break;
}
return (assemble_integer (x, size, force));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment