diff options
author | obrien <obrien@FreeBSD.org> | 2002-05-09 20:02:13 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2002-05-09 20:02:13 +0000 |
commit | c8f5fc7032940ad6633f932ac40cade82ec4d0cc (patch) | |
tree | 29a0f0a6c79a69ecc64f612947a0fe5904311713 /contrib/gcc/config/ia64 | |
parent | c9ab9ae440a8066b2c2b85b157b1fdadcf09916a (diff) | |
download | FreeBSD-src-c8f5fc7032940ad6633f932ac40cade82ec4d0cc.zip FreeBSD-src-c8f5fc7032940ad6633f932ac40cade82ec4d0cc.tar.gz |
Gcc 3.1.0 pre-release from the FSF anoncvs repo on 9-May-2002 15:57:15 EDT.
Diffstat (limited to 'contrib/gcc/config/ia64')
-rw-r--r-- | contrib/gcc/config/ia64/aix.h | 16 | ||||
-rw-r--r-- | contrib/gcc/config/ia64/elf.h | 6 | ||||
-rw-r--r-- | contrib/gcc/config/ia64/freebsd.h | 10 | ||||
-rw-r--r-- | contrib/gcc/config/ia64/hpux.h | 14 | ||||
-rw-r--r-- | contrib/gcc/config/ia64/ia64-protos.h | 4 | ||||
-rw-r--r-- | contrib/gcc/config/ia64/ia64.c | 322 | ||||
-rw-r--r-- | contrib/gcc/config/ia64/ia64.h | 59 | ||||
-rw-r--r-- | contrib/gcc/config/ia64/ia64.md | 33 | ||||
-rw-r--r-- | contrib/gcc/config/ia64/linux.h | 22 | ||||
-rw-r--r-- | contrib/gcc/config/ia64/sysv4.h | 5 | ||||
-rw-r--r-- | contrib/gcc/config/ia64/unwind-ia64.c | 298 |
11 files changed, 520 insertions, 269 deletions
diff --git a/contrib/gcc/config/ia64/aix.h b/contrib/gcc/config/ia64/aix.h index 1e57c2b..fee0732 100644 --- a/contrib/gcc/config/ia64/aix.h +++ b/contrib/gcc/config/ia64/aix.h @@ -86,9 +86,9 @@ Boston, MA 02111-1307, USA. */ #undef CPP_PREDEFINES #define CPP_PREDEFINES "\ --D__ia64 -D__ia64__ -D_AIX -D_AIX64 -D_LONGLONG -Dunix \ --D__LP64__ -D__ELF__ -Asystem=unix -Asystem=aix -Acpu=ia64 -Amachine=ia64 \ --D__64BIT__ -D_LONG_LONG -D_IA64 -D__int128=__size128_t" + -D_AIX -D_AIX64 -D_LONGLONG -Dunix \ + -Asystem=unix -Asystem=aix \ + -D__64BIT__ -D_LONG_LONG -D_IA64 -D__int128=__size128_t" /* The GNU C++ standard library requires that these macros be defined. */ #undef CPLUSPLUS_CPP_SPEC @@ -100,10 +100,6 @@ Boston, MA 02111-1307, USA. */ -D__LONG_MAX__=9223372036854775807L \ %{cpp_cpu}" -/* ia64-specific options for gas */ -#undef ASM_SPEC -#define ASM_SPEC "-x %{mconstant-gp} %{mauto-pic}" - /* Define this for shared library support. */ #undef LINK_SPEC @@ -115,14 +111,8 @@ Boston, MA 02111-1307, USA. */ %{!dynamic-linker:-dynamic-linker /usr/lib/ia64l64/libc.so.1}} \ %{static:-static}}" -#define DONT_USE_BUILTIN_SETJMP #define JMP_BUF_SIZE 85 -/* Output any profiling code before the prologue. */ - -#undef PROFILE_BEFORE_PROLOGUE -#define PROFILE_BEFORE_PROLOGUE 1 - /* A C statement or compound statement to output to FILE some assembler code to call the profiling subroutine `mcount'. diff --git a/contrib/gcc/config/ia64/elf.h b/contrib/gcc/config/ia64/elf.h index af8c7a6..af6d917 100644 --- a/contrib/gcc/config/ia64/elf.h +++ b/contrib/gcc/config/ia64/elf.h @@ -17,10 +17,12 @@ #if ((TARGET_CPU_DEFAULT | TARGET_DEFAULT) & MASK_GNU_AS) != 0 /* GNU AS. */ -#define ASM_SPEC \ - "%{mno-gnu-as:-N so} %{!mno-gnu-as:-x} %{mconstant-gp} %{mauto-pic}" +#undef ASM_EXTRA_SPEC +#define ASM_EXTRA_SPEC \ + "%{mno-gnu-as:-N so} %{!mno-gnu-as:-x}" #else /* Intel ias. */ +#undef ASM_SPEC #define ASM_SPEC \ "%{!mgnu-as:-N so} %{mgnu-as:-x} %{mconstant-gp:-M const_gp}\ %{mauto-pic:-M no_plabel}" diff --git a/contrib/gcc/config/ia64/freebsd.h b/contrib/gcc/config/ia64/freebsd.h index 6140128..57bb391 100644 --- a/contrib/gcc/config/ia64/freebsd.h +++ b/contrib/gcc/config/ia64/freebsd.h @@ -19,7 +19,6 @@ along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#undef LINK_SPEC #define LINK_SPEC \ "%{p:%e`-p' not supported; use `-pg' and gprof(1)} \ %{Wl,*:%*} \ @@ -32,9 +31,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ %{!dynamic-linker:-dynamic-linker /usr/libexec/ld-elf.so.1}} \ %{static:-Bstatic}}" -#undef ASM_SPEC -#define ASM_SPEC "-x %{mconstant-gp} %{mauto-pic}" - /************************[ Target stuff ]***********************************/ @@ -57,10 +53,4 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define TARGET_ELF 1 -#define DONT_USE_BUILTIN_SETJMP #define JMP_BUF_SIZE 76 - -/* Output any profiling code before the prologue. */ - -#undef PROFILE_BEFORE_PROLOGUE -#define PROFILE_BEFORE_PROLOGUE 1 diff --git a/contrib/gcc/config/ia64/hpux.h b/contrib/gcc/config/ia64/hpux.h index 89b2902..d46acf2 100644 --- a/contrib/gcc/config/ia64/hpux.h +++ b/contrib/gcc/config/ia64/hpux.h @@ -27,9 +27,9 @@ Boston, MA 02111-1307, USA. */ #undef CPP_PREDEFINES #define CPP_PREDEFINES "\ - -D__IA64__ -D__ia64 -D__ia64__ -D__hpux -D__hpux__ -Dhpux -Dunix \ - -D__BIG_ENDIAN__ -D_LONGLONG -D__ELF__ \ - -Asystem=hpux -Asystem=posix -Asystem=unix -Acpu=ia64 -Amachine=ia64 \ + -D__IA64__ -D__hpux -D__hpux__ -Dhpux -Dunix \ + -D__BIG_ENDIAN__ -D_LONGLONG \ + -Asystem=hpux -Asystem=posix -Asystem=unix \ -D_UINT128_T" /* -D__fpreg=long double is needed to compensate for the lack of __fpreg @@ -40,15 +40,14 @@ Boston, MA 02111-1307, USA. */ #undef CPP_SPEC #define CPP_SPEC "\ %{mcpu=itanium:-D__itanium__} \ - %{mlp64:-D__LP64__ -D__LONG_MAX__=9223372036854775807L} \ + %{mlp64:-D__LP64__ -D_LP64 -D__LONG_MAX__=9223372036854775807L} \ %{!ansi:%{!std=c*:%{!std=i*: -D_HPUX_SOURCE -D__STDC_EXT__}}} \ -D__fpreg=long\\ double \ -D__float80=long\\ double \ -D__float128=long\\ double" -#undef ASM_SPEC -#define ASM_SPEC "-x %{mconstant-gp} %{mauto-pic} \ - %{milp32:-milp32} %{mlp64:-mlp64}" +#undef ASM_EXTRA_SPEC +#define ASM_EXTRA_SPEC "%{milp32:-milp32} %{mlp64:-mlp64}" #undef ENDFILE_SPEC @@ -84,7 +83,6 @@ Boston, MA 02111-1307, USA. */ #define POINTERS_EXTEND_UNSIGNED -1 -#define DONT_USE_BUILTIN_SETJMP #define JMP_BUF_SIZE (8 * 76) #undef CONST_SECTION_ASM_OP diff --git a/contrib/gcc/config/ia64/ia64-protos.h b/contrib/gcc/config/ia64/ia64-protos.h index 43538cc..659adc5 100644 --- a/contrib/gcc/config/ia64/ia64-protos.h +++ b/contrib/gcc/config/ia64/ia64-protos.h @@ -113,6 +113,9 @@ extern int ia64_function_arg_partial_nregs PARAMS((CUMULATIVE_ARGS *, extern void ia64_function_arg_advance PARAMS((CUMULATIVE_ARGS *, enum machine_mode, tree, int)); +extern int ia64_function_arg_pass_by_reference PARAMS((CUMULATIVE_ARGS *, + enum machine_mode, + tree, int)); extern int ia64_return_in_memory PARAMS((tree)); extern void ia64_asm_output_external PARAMS((FILE *, tree, const char *)); @@ -122,6 +125,7 @@ extern void ia64_encode_section_info PARAMS((tree)); extern int ia64_register_move_cost PARAMS((enum machine_mode, enum reg_class, enum reg_class)); extern int ia64_epilogue_uses PARAMS((int)); +extern int ia64_eh_uses PARAMS((int)); extern void emit_safe_across_calls PARAMS((FILE *)); extern void ia64_init_builtins PARAMS((void)); extern void ia64_override_options PARAMS((void)); diff --git a/contrib/gcc/config/ia64/ia64.c b/contrib/gcc/config/ia64/ia64.c index 7ca060b..91dd396 100644 --- a/contrib/gcc/config/ia64/ia64.c +++ b/contrib/gcc/config/ia64/ia64.c @@ -24,7 +24,6 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "rtl.h" #include "tree.h" -#include "tm_p.h" #include "regs.h" #include "hard-reg-set.h" #include "real.h" @@ -46,6 +45,7 @@ Boston, MA 02111-1307, USA. */ #include "timevar.h" #include "target.h" #include "target-def.h" +#include "tm_p.h" /* This is used for communication between ASM_OUTPUT_LABEL and ASM_OUTPUT_LABELREF. */ @@ -138,7 +138,6 @@ static rtx ia64_expand_compare_and_swap PARAMS ((enum machine_mode, int, static rtx ia64_expand_lock_test_and_set PARAMS ((enum machine_mode, tree, rtx)); static rtx ia64_expand_lock_release PARAMS ((enum machine_mode, tree, rtx)); -const struct attribute_spec ia64_attribute_table[]; static bool ia64_assemble_integer PARAMS ((rtx, unsigned int, int)); static void ia64_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT)); static void ia64_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); @@ -156,6 +155,14 @@ static int ia64_variable_issue PARAMS ((FILE *, int, rtx, int)); static rtx ia64_cycle_display PARAMS ((int, rtx)); +/* Table of valid machine attributes. */ +static const struct attribute_spec ia64_attribute_table[] = +{ + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "syscall_linkage", 0, 0, false, true, true, NULL }, + { NULL, 0, 0, false, false, false, NULL } +}; + /* Initialize the GCC target structure. */ #undef TARGET_ATTRIBUTE_TABLE #define TARGET_ATTRIBUTE_TABLE ia64_attribute_table @@ -1137,7 +1144,8 @@ ia64_expand_call (retval, addr, nextarg, sibcall_p) rtx nextarg; int sibcall_p; { - rtx insn, b0, pfs, gp_save, narg_rtx; + rtx insn, b0, pfs, gp_save, narg_rtx, dest; + bool indirect_p; int narg; addr = XEXP (addr, 0); @@ -1164,61 +1172,36 @@ ia64_expand_call (retval, addr, nextarg, sibcall_p) return; } - if (sibcall_p) + indirect_p = ! symbolic_operand (addr, VOIDmode); + + if (sibcall_p || (TARGET_CONST_GP && !indirect_p)) gp_save = NULL_RTX; else gp_save = ia64_gp_save_reg (setjmp_operand (addr, VOIDmode)); + if (gp_save) + emit_move_insn (gp_save, pic_offset_table_rtx); + /* If this is an indirect call, then we have the address of a descriptor. */ - if (! symbolic_operand (addr, VOIDmode)) + if (indirect_p) { - rtx dest; - - if (! sibcall_p) - emit_move_insn (gp_save, pic_offset_table_rtx); - dest = force_reg (DImode, gen_rtx_MEM (DImode, addr)); emit_move_insn (pic_offset_table_rtx, gen_rtx_MEM (DImode, plus_constant (addr, 8))); - - if (sibcall_p) - insn = gen_sibcall_pic (dest, narg_rtx, b0, pfs); - else if (! retval) - insn = gen_call_pic (dest, narg_rtx, b0); - else - insn = gen_call_value_pic (retval, dest, narg_rtx, b0); - emit_call_insn (insn); - - if (! sibcall_p) - emit_move_insn (pic_offset_table_rtx, gp_save); - } - else if (TARGET_CONST_GP) - { - if (sibcall_p) - insn = gen_sibcall_nopic (addr, narg_rtx, b0, pfs); - else if (! retval) - insn = gen_call_nopic (addr, narg_rtx, b0); - else - insn = gen_call_value_nopic (retval, addr, narg_rtx, b0); - emit_call_insn (insn); } else - { - if (sibcall_p) - emit_call_insn (gen_sibcall_pic (addr, narg_rtx, b0, pfs)); - else - { - emit_move_insn (gp_save, pic_offset_table_rtx); + dest = addr; - if (! retval) - insn = gen_call_pic (addr, narg_rtx, b0); - else - insn = gen_call_value_pic (retval, addr, narg_rtx, b0); - emit_call_insn (insn); + if (sibcall_p) + insn = gen_sibcall_pic (dest, narg_rtx, b0, pfs); + else if (! retval) + insn = gen_call_pic (dest, narg_rtx, b0); + else + insn = gen_call_value_pic (retval, dest, narg_rtx, b0); + emit_call_insn (insn); - emit_move_insn (pic_offset_table_rtx, gp_save); - } - } + if (gp_save) + emit_move_insn (pic_offset_table_rtx, gp_save); } /* Begin the assembly file. */ @@ -2040,7 +2023,7 @@ ia64_expand_prologue () /* We don't need an alloc instruction if we've used no outputs or locals. */ if (current_frame_info.n_local_regs == 0 && current_frame_info.n_output_regs == 0 - && current_frame_info.n_input_regs <= current_function_args_info.words) + && current_frame_info.n_input_regs <= current_function_args_info.int_regs) { /* If there is no alloc, but there are input registers used, then we need a .regstk directive. */ @@ -2873,7 +2856,7 @@ hfa_element_mode (type, nested) return VOIDmode; case ARRAY_TYPE: - return TYPE_MODE (TREE_TYPE (type)); + return hfa_element_mode (TREE_TYPE (type), 1); case RECORD_TYPE: case UNION_TYPE: @@ -3181,14 +3164,14 @@ ia64_function_arg_advance (cum, mode, type, named) FR registers, then FP values must also go in general registers. This can happen when we have a SFmode HFA. */ else if (! FLOAT_MODE_P (mode) || cum->fp_regs == MAX_ARGUMENT_SLOTS) - return; + cum->int_regs = cum->words; /* If there is a prototype, then FP values go in a FR register when named, and in a GR registeer when unnamed. */ else if (cum->prototype) { if (! named) - return; + cum->int_regs = cum->words; else /* ??? Complex types should not reach here. */ cum->fp_regs += (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT ? 2 : 1); @@ -3196,10 +3179,24 @@ ia64_function_arg_advance (cum, mode, type, named) /* If there is no prototype, then FP values go in both FR and GR registers. */ else - /* ??? Complex types should not reach here. */ - cum->fp_regs += (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT ? 2 : 1); + { + /* ??? Complex types should not reach here. */ + cum->fp_regs += (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT ? 2 : 1); + cum->int_regs = cum->words; + } +} - return; +/* Variable sized types are passed by reference. */ +/* ??? At present this is a GCC extension to the IA-64 ABI. */ + +int +ia64_function_arg_pass_by_reference (cum, mode, type, named) + CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED; + enum machine_mode mode ATTRIBUTE_UNUSED; + tree type; + int named ATTRIBUTE_UNUSED; +{ + return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST; } /* Implement va_start. */ @@ -3232,6 +3229,13 @@ ia64_va_arg (valist, type) { tree t; + /* Variable sized types are passed by reference. */ + if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + { + rtx addr = std_expand_builtin_va_arg (valist, build_pointer_type (type)); + return gen_rtx_MEM (ptr_mode, force_reg (Pmode, addr)); + } + /* Arguments with alignment larger than 8 bytes start at the next even boundary. */ if (TYPE_ALIGN (type) > 8 * BITS_PER_UNIT) @@ -4765,6 +4769,7 @@ group_barrier_needed_p (insn) /* We play dependency tricks with the epilogue in order to get proper schedules. Undo this for dv analysis. */ case CODE_FOR_epilogue_deallocate_stack: + case CODE_FOR_prologue_allocate_stack: pat = XVECEXP (pat, 0, 0); break; @@ -5236,21 +5241,22 @@ ia64_single_set (insn) x = COND_EXEC_CODE (x); if (GET_CODE (x) == SET) return x; - ret = single_set_2 (insn, x); - if (ret == NULL && GET_CODE (x) == PARALLEL) - { - /* Special case here prologue_allocate_stack and - epilogue_deallocate_stack. Although it is not a classical - single set, the second set is there just to protect it - from moving past FP-relative stack accesses. */ - if (XVECLEN (x, 0) == 2 - && GET_CODE (XVECEXP (x, 0, 0)) == SET - && GET_CODE (XVECEXP (x, 0, 1)) == SET - && GET_CODE (SET_DEST (XVECEXP (x, 0, 1))) == REG - && SET_DEST (XVECEXP (x, 0, 1)) == SET_SRC (XVECEXP (x, 0, 1)) - && ia64_safe_itanium_class (insn) == ITANIUM_CLASS_IALU) - ret = XVECEXP (x, 0, 0); + + /* Special case here prologue_allocate_stack and epilogue_deallocate_stack. + Although they are not classical single set, the second set is there just + to protect it from moving past FP-relative stack accesses. */ + switch (recog_memoized (insn)) + { + case CODE_FOR_prologue_allocate_stack: + case CODE_FOR_epilogue_deallocate_stack: + ret = XVECEXP (x, 0, 0); + break; + + default: + ret = single_set_2 (insn, x); + break; } + return ret; } @@ -5348,6 +5354,7 @@ ia64_adjust_cost (insn, link, dep_insn, cost) if (reg_overlap_mentioned_p (SET_DEST (set), addr)) return cost + 1; } + if ((dep_class == ITANIUM_CLASS_IALU || dep_class == ITANIUM_CLASS_ILOG || dep_class == ITANIUM_CLASS_LD) @@ -5355,25 +5362,28 @@ ia64_adjust_cost (insn, link, dep_insn, cost) || insn_class == ITANIUM_CLASS_MMSHF || insn_class == ITANIUM_CLASS_MMSHFI)) return 3; + if (dep_class == ITANIUM_CLASS_FMAC && (insn_class == ITANIUM_CLASS_FMISC || insn_class == ITANIUM_CLASS_FCVTFX || insn_class == ITANIUM_CLASS_XMPY)) return 7; + if ((dep_class == ITANIUM_CLASS_FMAC || dep_class == ITANIUM_CLASS_FMISC || dep_class == ITANIUM_CLASS_FCVTFX || dep_class == ITANIUM_CLASS_XMPY) && insn_class == ITANIUM_CLASS_STF) return 8; + + /* Intel docs say only LD, ST, IALU, ILOG, ISHF consumers have latency 4, + but HP engineers say any non-MM operation. */ if ((dep_class == ITANIUM_CLASS_MMMUL || dep_class == ITANIUM_CLASS_MMSHF || dep_class == ITANIUM_CLASS_MMSHFI) - && (insn_class == ITANIUM_CLASS_LD - || insn_class == ITANIUM_CLASS_ST - || insn_class == ITANIUM_CLASS_IALU - || insn_class == ITANIUM_CLASS_ILOG - || insn_class == ITANIUM_CLASS_ISHF)) + && insn_class != ITANIUM_CLASS_MMMUL + && insn_class != ITANIUM_CLASS_MMSHF + && insn_class != ITANIUM_CLASS_MMSHFI) return 4; return cost; @@ -5475,32 +5485,6 @@ ia64_emit_insn_before (insn, before) emit_insn_before (insn, before); } -#if 0 -/* Generate a nop insn of the given type. Note we never generate L type - nops. */ - -static rtx -gen_nop_type (t) - enum attr_type t; -{ - switch (t) - { - case TYPE_M: - return gen_nop_m (); - case TYPE_I: - return gen_nop_i (); - case TYPE_B: - return gen_nop_b (); - case TYPE_F: - return gen_nop_f (); - case TYPE_X: - return gen_nop_x (); - default: - abort (); - } -} -#endif - /* When rotating a bundle out of the issue window, insert a bundle selector insn in front of it. DUMP is the scheduling dump file or NULL. START is either 0 or 3, depending on whether we want to emit a bundle selector @@ -5565,8 +5549,8 @@ cycle_end_fill_slots (dump) if (slot > sched_data.split) abort (); if (dump) - fprintf (dump, "// Packet needs %s, have %s\n", type_names[packet->t[slot]], - type_names[t]); + fprintf (dump, "// Packet needs %s, have %s\n", + type_names[packet->t[slot]], type_names[t]); sched_data.types[slot] = packet->t[slot]; sched_data.insns[slot] = 0; sched_data.stopbit[slot] = 0; @@ -5578,15 +5562,22 @@ cycle_end_fill_slots (dump) slot++; } + /* Do _not_ use T here. If T == TYPE_A, then we'd risk changing the actual slot type later. */ sched_data.types[slot] = packet->t[slot]; sched_data.insns[slot] = tmp_insns[i]; sched_data.stopbit[slot] = 0; slot++; + /* TYPE_L instructions always fill up two slots. */ if (t == TYPE_L) - slot++; + { + sched_data.types[slot] = packet->t[slot]; + sched_data.insns[slot] = 0; + sched_data.stopbit[slot] = 0; + slot++; + } } /* This isn't right - there's no need to pad out until the forced split; @@ -5629,6 +5620,8 @@ rotate_one_bundle (dump) memmove (sched_data.insns, sched_data.insns + 3, sched_data.cur * sizeof *sched_data.insns); + sched_data.packet + = &packets[(sched_data.packet->t2 - bundle) * NR_BUNDLES]; } else { @@ -6060,6 +6053,7 @@ static void maybe_rotate (dump) FILE *dump; { + cycle_end_fill_slots (dump); if (sched_data.cur == 6) rotate_two_bundles (dump); else if (sched_data.cur >= 3) @@ -6074,12 +6068,6 @@ static int prev_cycle; value of sched_data.first_slot. */ static int prev_first; -/* The last insn that has been scheduled. At the start of a new cycle - we know that we can emit new insns after it; the main scheduling code - has already emitted a cycle_display insn after it and is using that - as its current last insn. */ -static rtx last_issued; - /* Emit NOPs to fill the delay between PREV_CYCLE and CLOCK_VAR. Used to pad out the delay between MM (shifts, etc.) and integer operations. */ @@ -6090,12 +6078,13 @@ nop_cycles_until (clock_var, dump) { int prev_clock = prev_cycle; int cycles_left = clock_var - prev_clock; + bool did_stop = false; /* Finish the previous cycle; pad it out with NOPs. */ if (sched_data.cur == 3) { - rtx t = gen_insn_group_barrier (GEN_INT (3)); - last_issued = emit_insn_after (t, last_issued); + sched_emit_insn (gen_insn_group_barrier (GEN_INT (3))); + did_stop = true; maybe_rotate (dump); } else if (sched_data.cur > 0) @@ -6114,12 +6103,9 @@ nop_cycles_until (clock_var, dump) int i; for (i = sched_data.cur; i < split; i++) { - rtx t; - - t = gen_nop_type (sched_data.packet->t[i]); - last_issued = emit_insn_after (t, last_issued); - sched_data.types[i] = sched_data.packet->t[sched_data.cur]; - sched_data.insns[i] = last_issued; + rtx t = sched_emit_insn (gen_nop_type (sched_data.packet->t[i])); + sched_data.types[i] = sched_data.packet->t[i]; + sched_data.insns[i] = t; sched_data.stopbit[i] = 0; } sched_data.cur = split; @@ -6131,12 +6117,9 @@ nop_cycles_until (clock_var, dump) int i; for (i = sched_data.cur; i < 6; i++) { - rtx t; - - t = gen_nop_type (sched_data.packet->t[i]); - last_issued = emit_insn_after (t, last_issued); - sched_data.types[i] = sched_data.packet->t[sched_data.cur]; - sched_data.insns[i] = last_issued; + rtx t = sched_emit_insn (gen_nop_type (sched_data.packet->t[i])); + sched_data.types[i] = sched_data.packet->t[i]; + sched_data.insns[i] = t; sched_data.stopbit[i] = 0; } sched_data.cur = 6; @@ -6146,8 +6129,8 @@ nop_cycles_until (clock_var, dump) if (need_stop || sched_data.cur == 6) { - rtx t = gen_insn_group_barrier (GEN_INT (3)); - last_issued = emit_insn_after (t, last_issued); + sched_emit_insn (gen_insn_group_barrier (GEN_INT (3))); + did_stop = true; } maybe_rotate (dump); } @@ -6155,24 +6138,22 @@ nop_cycles_until (clock_var, dump) cycles_left--; while (cycles_left > 0) { - rtx t = gen_bundle_selector (GEN_INT (0)); - last_issued = emit_insn_after (t, last_issued); - t = gen_nop_type (TYPE_M); - last_issued = emit_insn_after (t, last_issued); - t = gen_nop_type (TYPE_I); - last_issued = emit_insn_after (t, last_issued); + sched_emit_insn (gen_bundle_selector (GEN_INT (0))); + sched_emit_insn (gen_nop_type (TYPE_M)); + sched_emit_insn (gen_nop_type (TYPE_I)); if (cycles_left > 1) { - t = gen_insn_group_barrier (GEN_INT (2)); - last_issued = emit_insn_after (t, last_issued); + sched_emit_insn (gen_insn_group_barrier (GEN_INT (2))); cycles_left--; } - t = gen_nop_type (TYPE_I); - last_issued = emit_insn_after (t, last_issued); - t = gen_insn_group_barrier (GEN_INT (3)); - last_issued = emit_insn_after (t, last_issued); + sched_emit_insn (gen_nop_type (TYPE_I)); + sched_emit_insn (gen_insn_group_barrier (GEN_INT (3))); + did_stop = true; cycles_left--; } + + if (did_stop) + init_insn_group_barriers (); } /* We are about to being issuing insns for this clock cycle. @@ -6198,31 +6179,34 @@ ia64_internal_sched_reorder (dump, sched_verbose, ready, pn_ready, dump_current_packet (dump); } + /* Work around the pipeline flush that will occurr if the results of + an MM instruction are accessed before the result is ready. Intel + documentation says this only happens with IALU, ISHF, ILOG, LD, + and ST consumers, but experimental evidence shows that *any* non-MM + type instruction will incurr the flush. */ if (reorder_type == 0 && clock_var > 0 && ia64_final_schedule) { for (insnp = ready; insnp < e_ready; insnp++) { - rtx insn = *insnp; + rtx insn = *insnp, link; enum attr_itanium_class t = ia64_safe_itanium_class (insn); - if (t == ITANIUM_CLASS_IALU || t == ITANIUM_CLASS_ISHF - || t == ITANIUM_CLASS_ILOG - || t == ITANIUM_CLASS_LD || t == ITANIUM_CLASS_ST) - { - rtx link; - for (link = LOG_LINKS (insn); link; link = XEXP (link, 1)) - if (REG_NOTE_KIND (link) != REG_DEP_OUTPUT - && REG_NOTE_KIND (link) != REG_DEP_ANTI) + + if (t == ITANIUM_CLASS_MMMUL + || t == ITANIUM_CLASS_MMSHF + || t == ITANIUM_CLASS_MMSHFI) + continue; + + for (link = LOG_LINKS (insn); link; link = XEXP (link, 1)) + if (REG_NOTE_KIND (link) == 0) + { + rtx other = XEXP (link, 0); + enum attr_itanium_class t0 = ia64_safe_itanium_class (other); + if (t0 == ITANIUM_CLASS_MMSHF || t0 == ITANIUM_CLASS_MMMUL) { - rtx other = XEXP (link, 0); - enum attr_itanium_class t0 = ia64_safe_itanium_class (other); - if (t0 == ITANIUM_CLASS_MMSHF - || t0 == ITANIUM_CLASS_MMMUL) - { - nop_cycles_until (clock_var, sched_verbose ? dump : NULL); - goto out; - } + nop_cycles_until (clock_var, sched_verbose ? dump : NULL); + goto out; } - } + } } } out: @@ -6486,8 +6470,6 @@ ia64_variable_issue (dump, sched_verbose, insn, can_issue_more) { enum attr_type t = ia64_safe_type (insn); - last_issued = insn; - if (sched_data.last_was_stop) { int t = sched_data.first_slot; @@ -6833,13 +6815,33 @@ ia64_epilogue_uses (regno) } } -/* Table of valid machine attributes. */ -const struct attribute_spec ia64_attribute_table[] = +/* Return true if REGNO is used by the frame unwinder. */ + +int +ia64_eh_uses (regno) + int regno; { - /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ - { "syscall_linkage", 0, 0, false, true, true, NULL }, - { NULL, 0, 0, false, false, false, NULL } -}; + if (! reload_completed) + return 0; + + if (current_frame_info.reg_save_b0 + && regno == current_frame_info.reg_save_b0) + return 1; + if (current_frame_info.reg_save_pr + && regno == current_frame_info.reg_save_pr) + return 1; + if (current_frame_info.reg_save_ar_pfs + && regno == current_frame_info.reg_save_ar_pfs) + return 1; + if (current_frame_info.reg_save_ar_unat + && regno == current_frame_info.reg_save_ar_unat) + return 1; + if (current_frame_info.reg_save_ar_lc + && regno == current_frame_info.reg_save_ar_lc) + return 1; + + return 0; +} /* For ia64, SYMBOL_REF_FLAG set means that it is a function. diff --git a/contrib/gcc/config/ia64/ia64.h b/contrib/gcc/config/ia64/ia64.h index 1900717..f69983b 100644 --- a/contrib/gcc/config/ia64/ia64.h +++ b/contrib/gcc/config/ia64/ia64.h @@ -31,12 +31,19 @@ Boston, MA 02111-1307, USA. */ /* Run-time target specifications */ -#define CPP_CPU_SPEC "\ - -Acpu=ia64 -Amachine=ia64 \ - %{!ansi:%{!std=c*:%{!std=i*:-Dia64}}} -D__ia64 -D__ia64__" +#define EXTRA_SPECS \ + { "cpp_cpu", CPP_CPU_SPEC }, \ + { "asm_extra", ASM_EXTRA_SPEC }, + +#define CPP_CPU_SPEC " \ + -Acpu=ia64 -Amachine=ia64 -D__ia64 -D__ia64__ %{!milp32:-D_LP64 -D__LP64__} \ + -D__ELF__" #define CC1_SPEC "%(cc1_cpu) " +#define ASM_EXTRA_SPEC "" + + /* This declaration should be present. */ extern int target_flags; @@ -203,6 +210,7 @@ extern const char *ia64_fixed_range_string; defines in other tm.h files. */ #define CPP_SPEC \ "%{mcpu=itanium:-D__itanium__} %{mbig-endian:-D__BIG_ENDIAN__} \ + %(cpp_cpu) \ -D__LONG_MAX__=9223372036854775807L" /* This is always "long" so it doesn't "change" in ILP32 vs. LP64. */ @@ -340,7 +348,7 @@ while (0) /* By default, the C++ compiler will use function addresses in the vtable entries. Setting this non-zero tells the compiler to use function descriptors instead. The value of this macro says how - many words wide the descriptor is (normally 2). It is assumed + many words wide the descriptor is (normally 2). It is assumed that the address of a function descriptor may be treated as a pointer to a function. */ #define TARGET_VTABLE_USES_DESCRIPTORS 2 @@ -397,7 +405,7 @@ while (0) /* Register Basics */ -/* Number of hardware registers known to the compiler. +/* Number of hardware registers known to the compiler. We have 128 general registers, 128 floating point registers, 64 predicate registers, 8 branch registers, one frame pointer, and several "application" registers. */ @@ -459,7 +467,7 @@ while (0) f0: constant 0.0 f1: constant 1.0 p0: constant true - fp: eliminable frame pointer */ + fp: eliminable frame pointer */ /* The last 16 stacked regs are reserved for the 8 input and 8 output registers. */ @@ -529,12 +537,12 @@ while (0) 1, 1, 1, 1, 1, 0, 1 \ } -/* Like `CALL_USED_REGISTERS' but used to overcome a historical +/* Like `CALL_USED_REGISTERS' but used to overcome a historical problem which makes CALL_USED_REGISTERS *always* include - all the FIXED_REGISTERS. Until this problem has been + all the FIXED_REGISTERS. Until this problem has been resolved this macro can be used to overcome this situation. - In particular, block_propagate() requires this list - be acurate, or we can remove registers which should be live. + In particular, block_propagate() requires this list + be acurate, or we can remove registers which should be live. This macro is used in regs_invalidated_by_call. */ #define CALL_REALLY_USED_REGISTERS \ @@ -1151,6 +1159,14 @@ enum reg_class in it. */ #define ARG_POINTER_REGNUM R_GR(0) +/* Due to the way varargs and argument spilling happens, the argument + pointer is not 16-byte aligned like the stack pointer. */ +#define INIT_EXPANDERS \ + do { \ + if (cfun && cfun->emit->regno_pointer_align) \ + REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) = 64; \ + } while (0) + /* The register number for the return address register. For IA-64, this is not actually a pointer as the name suggests, but that's a name that gen_rtx_REG already takes care to keep unique. We modify @@ -1258,7 +1274,8 @@ enum reg_class pointer is passed in whatever way is appropriate for passing a pointer to that type. */ -#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) 0 +#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \ + ia64_function_arg_pass_by_reference (&CUM, MODE, TYPE, NAMED) /* A C type for declaring a variable that is used as the first argument of `FUNCTION_ARG' and other related values. For some target machines, the type @@ -1267,6 +1284,7 @@ enum reg_class typedef struct ia64_args { int words; /* # words of arguments so far */ + int int_regs; /* # GR registers used so far */ int fp_regs; /* # FR registers used so far */ int prototype; /* whether function prototyped */ } CUMULATIVE_ARGS; @@ -1277,6 +1295,7 @@ typedef struct ia64_args #define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ do { \ (CUM).words = 0; \ + (CUM).int_regs = 0; \ (CUM).fp_regs = 0; \ (CUM).prototype = ((FNTYPE) && TYPE_ARG_TYPES (FNTYPE)) || (LIBNAME); \ } while (0) @@ -1290,6 +1309,7 @@ do { \ #define INIT_CUMULATIVE_INCOMING_ARGS(CUM, FNTYPE, LIBNAME) \ do { \ (CUM).words = 0; \ + (CUM).int_regs = 0; \ (CUM).fp_regs = 0; \ (CUM).prototype = 1; \ } while (0) @@ -1355,7 +1375,7 @@ do { \ #define FUNCTION_VALUE_REGNO_P(REGNO) \ (((REGNO) >= GR_RET_FIRST && (REGNO) <= GR_RET_LAST) \ - || ((REGNO) >= FR_RET_FIRST && (REGNO) <= FR_RET_LAST)) + || ((REGNO) >= FR_RET_FIRST && (REGNO) <= FR_RET_LAST)) /* How Large Values are Returned */ @@ -1404,6 +1424,10 @@ do { \ #define EPILOGUE_USES(REGNO) ia64_epilogue_uses (REGNO) +/* Nonzero for registers used by the exception handling mechanism. */ + +#define EH_USES(REGNO) ia64_eh_uses (REGNO) + /* Output at beginning of assembler file. */ #define ASM_FILE_START(FILE) \ @@ -1722,7 +1746,7 @@ do { \ || (CLASS) == GR_AND_FR_REGS ? 4 : 10) /* A C expression for the cost of a branch instruction. A value of 1 is the - default; other values are interpreted relative to that. Used by the + default; other values are interpreted relative to that. Used by the if-conversion code as max instruction count. */ /* ??? This requires investigation. The primary effect might be how many additional insn groups we run into, vs how good the dynamic @@ -2273,7 +2297,7 @@ do { \ fprintf (FILE, "[.%s%d:]\n", PREFIX, NUM) /* Use section-relative relocations for debugging offsets. Unlike other - targets that fake this by putting the section VMA at 0, IA-64 has + targets that fake this by putting the section VMA at 0, IA-64 has proper relocations for them. */ #define ASM_OUTPUT_DWARF_OFFSET(FILE, SIZE, LABEL) \ do { \ @@ -2527,4 +2551,11 @@ enum fetchop_code { IA64_ADD_OP, IA64_SUB_OP, IA64_OR_OP, IA64_AND_OP, IA64_XOR_OP, IA64_NAND_OP }; +#define DONT_USE_BUILTIN_SETJMP + +/* Output any profiling code before the prologue. */ + +#undef PROFILE_BEFORE_PROLOGUE +#define PROFILE_BEFORE_PROLOGUE 1 + /* End of ia64.h */ diff --git a/contrib/gcc/config/ia64/ia64.md b/contrib/gcc/config/ia64/ia64.md index c88e8b0..7b11c06 100644 --- a/contrib/gcc/config/ia64/ia64.md +++ b/contrib/gcc/config/ia64/ia64.md @@ -4848,7 +4848,7 @@ [(set (match_operand:DI 0 "register_operand" "=r,r,r") (plus:DI (match_operand:DI 1 "register_operand" "%r,r,a") (match_operand:DI 2 "gr_reg_or_22bit_operand" "r,I,J"))) - (set (match_operand:DI 3 "register_operand" "=r,r,r") + (set (match_operand:DI 3 "register_operand" "+r,r,r") (match_dup 3))] "" "@ @@ -5045,6 +5045,37 @@ [(set_attr "itanium_class" "stop_bit") (set_attr "predicable" "no")]) +(define_expand "trap" + [(trap_if (const_int 1) (const_int 0))] + "" + "") + +;; ??? We don't have a match-any slot type. Setting the type to unknown +;; produces worse code that setting the slot type to A. + +(define_insn "*trap" + [(trap_if (const_int 1) (match_operand 0 "const_int_operand" ""))] + "" + "break %0" + [(set_attr "itanium_class" "chk_s")]) + +(define_expand "conditional_trap" + [(trap_if (match_operand 0 "" "") (match_operand 1 "" ""))] + "" +{ + operands[0] = ia64_expand_compare (GET_CODE (operands[0]), VOIDmode); +}) + +(define_insn "*conditional_trap" + [(trap_if (match_operator 0 "predicate_operator" + [(match_operand:BI 1 "register_operand" "c") + (const_int 0)]) + (match_operand 2 "const_int_operand" ""))] + "" + "(%J0) break %2" + [(set_attr "itanium_class" "chk_s") + (set_attr "predicable" "no")]) + (define_insn "break_f" [(unspec_volatile [(const_int 0)] 3)] "" diff --git a/contrib/gcc/config/ia64/linux.h b/contrib/gcc/config/ia64/linux.h index 1889ef6..3091852 100644 --- a/contrib/gcc/config/ia64/linux.h +++ b/contrib/gcc/config/ia64/linux.h @@ -11,12 +11,8 @@ /* ??? Maybe this should be in sysv4.h? */ #define CPP_PREDEFINES "\ --D__ia64 -D__ia64__ -D__linux -D__linux__ -D_LONGLONG -Dlinux -Dunix \ --D__LP64__ -D__ELF__ -Asystem=linux -Acpu=ia64 -Amachine=ia64" - -/* ??? ia64 gas doesn't accept standard svr4 assembler options? */ -#undef ASM_SPEC -#define ASM_SPEC "-x %{mconstant-gp} %{mauto-pic}" + -D__gnu_linux__ -D__linux -D__linux__ -D_LONGLONG \ + -Dlinux -Dunix -Asystem=linux" /* Need to override linux.h STARTFILE_SPEC, since it has crtbeginT.o in. */ #undef STARTFILE_SPEC @@ -46,14 +42,8 @@ %{static:-static}}" -#define DONT_USE_BUILTIN_SETJMP #define JMP_BUF_SIZE 76 -/* Output any profiling code before the prologue. */ - -#undef PROFILE_BEFORE_PROLOGUE -#define PROFILE_BEFORE_PROLOGUE 1 - /* Override linux.h LINK_EH_SPEC definition. Signalize that because we have fde-glibc, we don't need all C shared libs linked against -lgcc_s. */ @@ -98,10 +88,16 @@ (CONTEXT)->pfs_loc = &(sc_->sc_ar_pfs); \ (CONTEXT)->lc_loc = &(sc_->sc_ar_lc); \ (CONTEXT)->unat_loc = &(sc_->sc_ar_unat); \ + (CONTEXT)->br_loc[0] = &(sc_->sc_br[0]); \ + (CONTEXT)->bsp = sc_->sc_ar_bsp; \ (CONTEXT)->pr = sc_->sc_pr; \ (CONTEXT)->psp = sc_->sc_gr[12]; \ + (CONTEXT)->gp = sc_->sc_gr[1]; \ + /* Signal frame doesn't have an associated reg. stack frame \ + other than what we adjust for below. */ \ + (FS) -> no_reg_stack_frame = 1; \ \ - /* Don't touch the branch registers. The kernel doesn't \ + /* Don't touch the branch registers o.t. b0. The kernel doesn't \ pass the preserved branch registers in the sigcontext but \ leaves them intact, so there's no need to do anything \ with them here. */ \ diff --git a/contrib/gcc/config/ia64/sysv4.h b/contrib/gcc/config/ia64/sysv4.h index 1b5d469..c53a1dc 100644 --- a/contrib/gcc/config/ia64/sysv4.h +++ b/contrib/gcc/config/ia64/sysv4.h @@ -22,6 +22,11 @@ #undef ASCII_DATA_ASM_OP #define ASCII_DATA_ASM_OP "\tstring\t" +/* ia64-specific options for gas + ??? ia64 gas doesn't accept standard svr4 assembler options? */ +#undef ASM_SPEC +#define ASM_SPEC "-x %{mconstant-gp} %{mauto-pic} %(asm_extra)" + /* ??? Unfortunately, .lcomm doesn't work, because it puts things in either .bss or .sbss, and we can't control the decision of which is used. When I use .lcomm, I get a cryptic "Section group has no member" error from diff --git a/contrib/gcc/config/ia64/unwind-ia64.c b/contrib/gcc/config/ia64/unwind-ia64.c index 99923aa..ca91539 100644 --- a/contrib/gcc/config/ia64/unwind-ia64.c +++ b/contrib/gcc/config/ia64/unwind-ia64.c @@ -35,6 +35,10 @@ #include "tsystem.h" #include "unwind.h" #include "unwind-ia64.h" +#include "ia64intrin.h" + +/* This isn't thread safe, but nice for occasional tests. */ +#undef ENABLE_MALLOC_CHECKING #ifndef __USING_SJLJ_EXCEPTIONS__ #define UNW_VER(x) ((x) >> 48) @@ -121,13 +125,24 @@ struct unw_reg_info int when; /* when the register gets saved */ }; +struct unw_reg_state { + struct unw_reg_state *next; /* next (outer) element on state stack */ + struct unw_reg_info reg[UNW_NUM_REGS]; /* register save locations */ +}; + +struct unw_labeled_state { + struct unw_labeled_state *next; /* next labeled state (or NULL) */ + unsigned long label; /* label for this state */ + struct unw_reg_state saved_state; +}; + typedef struct unw_state_record { unsigned int first_region : 1; /* is this the first region? */ unsigned int done : 1; /* are we done scanning descriptors? */ unsigned int any_spills : 1; /* got any register spills? */ unsigned int in_body : 1; /* are we inside a body? */ - + unsigned int no_reg_stack_frame : 1; /* Don't adjust bsp for i&l regs */ unsigned char *imask; /* imask of of spill_mask record or NULL */ unsigned long pr_val; /* predicate values */ unsigned long pr_mask; /* predicate mask */ @@ -141,11 +156,8 @@ typedef struct unw_state_record unsigned char gr_save_loc; /* next general register to use for saving */ unsigned char return_link_reg; /* branch register for return link */ - struct unw_reg_state { - struct unw_reg_state *next; - unsigned long label; /* label of this state record */ - struct unw_reg_info reg[UNW_NUM_REGS]; - } curr, *stack, *reg_state_list; + struct unw_labeled_state *labeled_states; /* list of all labeled states */ + struct unw_reg_state curr; /* current state */ _Unwind_Personality_Fn personality; @@ -184,9 +196,12 @@ struct _Unwind_Context void *lsda; /* language specific data area */ /* Preserved state. */ - unsigned long *bsp_loc; /* previous bsp save location */ + unsigned long *bsp_loc; /* previous bsp save location + Appears to be write-only? */ unsigned long *bspstore_loc; - unsigned long *pfs_loc; + unsigned long *pfs_loc; /* Save location for pfs in current + (corr. to sp) frame. Target + contains cfm for caller. */ unsigned long *pri_unat_loc; unsigned long *unat_loc; unsigned long *lc_loc; @@ -226,28 +241,196 @@ static unsigned char const save_order[] = #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) -/* Unwind decoder routines */ +/* MASK is a bitmap describing the allocation state of emergency buffers, + with bit set indicating free. Return >= 0 if allocation is successful; + < 0 if failure. */ -static void -push (struct unw_state_record *sr) +static inline int +atomic_alloc (unsigned int *mask) +{ + unsigned int old = *mask, ret, new; + + while (1) + { + if (old == 0) + return -1; + ret = old & -old; + new = old & ~ret; + new = __sync_val_compare_and_swap (mask, old, new); + if (old == new) + break; + old = new; + } + + return __builtin_ffs (ret) - 1; +} + +/* Similarly, free an emergency buffer. */ + +static inline void +atomic_free (unsigned int *mask, int bit) +{ + __sync_xor_and_fetch (mask, 1 << bit); +} + + +#define SIZE(X) (sizeof(X) / sizeof(*(X))) +#define MASK_FOR(X) ((2U << (SIZE (X) - 1)) - 1) +#define PTR_IN(X, P) ((P) >= (X) && (P) < (X) + SIZE (X)) + +static struct unw_reg_state emergency_reg_state[32]; +static int emergency_reg_state_free = MASK_FOR (emergency_reg_state); + +static struct unw_labeled_state emergency_labeled_state[8]; +static int emergency_labeled_state_free = MASK_FOR (emergency_labeled_state); + +#ifdef ENABLE_MALLOC_CHECKING +static int reg_state_alloced; +static int labeled_state_alloced; +#endif + +/* Allocation and deallocation of structures. */ + +static struct unw_reg_state * +alloc_reg_state (void) { struct unw_reg_state *rs; +#ifdef ENABLE_MALLOC_CHECKING + reg_state_alloced++; +#endif + rs = malloc (sizeof (struct unw_reg_state)); + if (!rs) + { + int n = atomic_alloc (&emergency_reg_state_free); + if (n >= 0) + rs = &emergency_reg_state[n]; + } + + return rs; +} + +static void +free_reg_state (struct unw_reg_state *rs) +{ +#ifdef ENABLE_MALLOC_CHECKING + reg_state_alloced--; +#endif + + if (PTR_IN (emergency_reg_state, rs)) + atomic_free (&emergency_reg_state_free, rs - emergency_reg_state); + else + free (rs); +} + +static struct unw_labeled_state * +alloc_label_state (void) +{ + struct unw_labeled_state *ls; + +#ifdef ENABLE_MALLOC_CHECKING + labeled_state_alloced++; +#endif + + ls = malloc(sizeof(struct unw_labeled_state)); + if (!ls) + { + int n = atomic_alloc (&emergency_labeled_state_free); + if (n >= 0) + ls = &emergency_labeled_state[n]; + } + + return ls; +} + +static void +free_label_state (struct unw_labeled_state *ls) +{ +#ifdef ENABLE_MALLOC_CHECKING + labeled_state_alloced--; +#endif + + if (PTR_IN (emergency_labeled_state, ls)) + atomic_free (&emergency_labeled_state_free, emergency_labeled_state - ls); + else + free (ls); +} + +/* Routines to manipulate the state stack. */ + +static void +push (struct unw_state_record *sr) +{ + struct unw_reg_state *rs = alloc_reg_state (); memcpy (rs, &sr->curr, sizeof (*rs)); - rs->next = sr->stack; - sr->stack = rs; + sr->curr.next = rs; } static void pop (struct unw_state_record *sr) { - struct unw_reg_state *rs; + struct unw_reg_state *rs = sr->curr.next; + + if (!rs) + abort (); + memcpy (&sr->curr, rs, sizeof(*rs)); + free_reg_state (rs); +} + +/* Make a copy of the state stack. Non-recursive to avoid stack overflows. */ + +static struct unw_reg_state * +dup_state_stack (struct unw_reg_state *rs) +{ + struct unw_reg_state *copy, *prev = NULL, *first = NULL; + + while (rs) + { + copy = alloc_reg_state (); + memcpy (copy, rs, sizeof(*copy)); + if (first) + prev->next = copy; + else + first = copy; + rs = rs->next; + prev = copy; + } + + return first; +} + +/* Free all stacked register states (but not RS itself). */ +static void +free_state_stack (struct unw_reg_state *rs) +{ + struct unw_reg_state *p, *next; - rs = sr->stack; - sr->stack = rs->next; - free (rs); + for (p = rs->next; p != NULL; p = next) + { + next = p->next; + free_reg_state (p); + } + rs->next = NULL; +} + +/* Free all labeled states. */ + +static void +free_label_states (struct unw_labeled_state *ls) +{ + struct unw_labeled_state *next; + + for (; ls ; ls = next) + { + next = ls->next; + + free_state_stack (&ls->saved_state); + free_label_state (ls); + } } + +/* Unwind decoder routines */ static enum unw_register_index __attribute__((const)) decode_abreg (unsigned char abreg, int memory) @@ -295,8 +478,8 @@ alloc_spill_area (unsigned long *offp, unsigned long regsize, if (reg->where == UNW_WHERE_SPILL_HOME) { reg->where = UNW_WHERE_PSPREL; - reg->val = 0x10 - *offp; - *offp += regsize; + *offp -= regsize; + reg->val = *offp; } } } @@ -330,7 +513,7 @@ finish_prologue (struct unw_state_record *sr) /* First, resolve implicit register save locations (see Section "11.4.2.3 Rules for Using Unwind Descriptors", rule 3). */ - for (i = 0; i < (int) sizeof(save_order); ++i) + for (i = 0; i < (int) sizeof (save_order); ++i) { reg = sr->curr.reg + save_order[i]; if (reg->where == UNW_WHERE_GR_SAVE) @@ -363,8 +546,8 @@ finish_prologue (struct unw_state_record *sr) mask = *cp++; kind = (mask >> 2*(3-(t & 3))) & 3; if (kind > 0) - spill_next_when(®s[kind - 1], sr->curr.reg + limit[kind - 1], - sr->region_start + t); + spill_next_when (®s[kind - 1], sr->curr.reg + limit[kind - 1], + sr->region_start + t); } } @@ -372,12 +555,12 @@ finish_prologue (struct unw_state_record *sr) if (sr->any_spills) { off = sr->spill_offset; - alloc_spill_area(&off, 16, sr->curr.reg + UNW_REG_F2, - sr->curr.reg + UNW_REG_F31); - alloc_spill_area(&off, 8, sr->curr.reg + UNW_REG_B1, - sr->curr.reg + UNW_REG_B5); - alloc_spill_area(&off, 8, sr->curr.reg + UNW_REG_R4, - sr->curr.reg + UNW_REG_R7); + alloc_spill_area (&off, 16, sr->curr.reg + UNW_REG_F2, + sr->curr.reg + UNW_REG_F31); + alloc_spill_area (&off, 8, sr->curr.reg + UNW_REG_B1, + sr->curr.reg + UNW_REG_B5); + alloc_spill_area (&off, 8, sr->curr.reg + UNW_REG_R4, + sr->curr.reg + UNW_REG_R7); } } @@ -392,23 +575,24 @@ desc_prologue (int body, unw_word rlen, unsigned char mask, int i; if (!(sr->in_body || sr->first_region)) - finish_prologue(sr); + finish_prologue (sr); sr->first_region = 0; /* Check if we're done. */ - if (body && sr->when_target < sr->region_start + sr->region_len) + if (sr->when_target < sr->region_start + sr->region_len) { sr->done = 1; return; } for (i = 0; i < sr->epilogue_count; ++i) - pop(sr); + pop (sr); + sr->epilogue_count = 0; sr->epilogue_start = UNW_WHEN_NEVER; if (!body) - push(sr); + push (sr); sr->region_start += sr->region_len; sr->region_len = rlen; @@ -494,7 +678,8 @@ desc_frgr_mem (unsigned char grmask, unw_word frmask, { if ((frmask & 1) != 0) { - set_reg (sr->curr.reg + UNW_REG_F2 + i, UNW_WHERE_SPILL_HOME, + enum unw_register_index base = i < 4 ? UNW_REG_F2 : UNW_REG_F16 - 4; + set_reg (sr->curr.reg + base + i, UNW_WHERE_SPILL_HOME, sr->region_start + sr->region_len - 1, 0); sr->any_spills = 1; } @@ -631,13 +816,15 @@ desc_epilogue (unw_word t, unw_word ecount, struct unw_state_record *sr) static inline void desc_copy_state (unw_word label, struct unw_state_record *sr) { - struct unw_reg_state *rs; + struct unw_labeled_state *ls; - for (rs = sr->reg_state_list; rs; rs = rs->next) + for (ls = sr->labeled_states; ls; ls = ls->next) { - if (rs->label == label) - { - memcpy (&sr->curr, rs, sizeof(sr->curr)); + if (ls->label == label) + { + free_state_stack (&sr->curr); + memcpy (&sr->curr, &ls->saved_state, sizeof (sr->curr)); + sr->curr.next = dup_state_stack (ls->saved_state.next); return; } } @@ -647,13 +834,15 @@ desc_copy_state (unw_word label, struct unw_state_record *sr) static inline void desc_label_state (unw_word label, struct unw_state_record *sr) { - struct unw_reg_state *rs; + struct unw_labeled_state *ls = alloc_label_state (); - rs = malloc (sizeof (struct unw_reg_state)); - memcpy (rs, &sr->curr, sizeof (*rs)); - rs->label = label; - rs->next = sr->reg_state_list; - sr->reg_state_list = rs; + ls->label = label; + memcpy (&ls->saved_state, &sr->curr, sizeof (ls->saved_state)); + ls->saved_state.next = dup_state_stack (sr->curr.next); + + /* Insert into list of labeled states. */ + ls->next = sr->labeled_states; + sr->labeled_states = ls; } /* @@ -1461,8 +1650,11 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) unsigned long *unw, header, length; unsigned char *insn, *insn_end; unsigned long segment_base; + struct unw_reg_info *r; memset (fs, 0, sizeof (*fs)); + for (r = fs->curr.reg; r < fs->curr.reg + UNW_NUM_REGS; ++r) + r->when = UNW_WHEN_NEVER; context->lsda = 0; ent = _Unwind_FindTableEntry ((void *) context->rp, @@ -1518,6 +1710,14 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) while (!fs->done && insn < insn_end) insn = unw_decode (insn, fs->in_body, fs); + free_label_states (fs->labeled_states); + free_state_stack (&fs->curr); + +#ifdef ENABLE_MALLOC_CHECKING + if (reg_state_alloced || labeled_state_alloced) + abort (); +#endif + /* If we're in the epilogue, sp has been restored and all values on the memory stack below psp also have been restored. */ if (fs->when_target > fs->epilogue_start) @@ -1578,7 +1778,7 @@ uw_update_reg_address (struct _Unwind_Context *context, /* Note that while RVAL can only be 1-5 from normal descriptors, we can want to look at B0 due to having manually unwound a signal frame. */ - if (rval >= 0 && rval <= 5) + if (rval <= 5) addr = context->br_loc[rval]; else abort (); @@ -1677,8 +1877,7 @@ uw_update_reg_address (struct _Unwind_Context *context, context->psp = *(unsigned long *)addr; break; - case UNW_REG_RNAT: - case UNW_NUM_REGS: + default: abort (); } } @@ -1720,7 +1919,10 @@ uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) /* Unwind BSP for the local registers allocated this frame. */ /* ??? What to do with stored BSP or BSPSTORE registers. */ - if (fs->when_target > fs->curr.reg[UNW_REG_PFS].when) + /* We assert that we are either at a call site, or we have + just unwound through a signal frame. In either case + pfs_loc is valid. */ + if (!(fs -> no_reg_stack_frame)) { unsigned long pfs = *context->pfs_loc; unsigned long sol = (pfs >> 7) & 0x7f; |