summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/config/ia64
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2002-05-09 20:02:13 +0000
committerobrien <obrien@FreeBSD.org>2002-05-09 20:02:13 +0000
commitc8f5fc7032940ad6633f932ac40cade82ec4d0cc (patch)
tree29a0f0a6c79a69ecc64f612947a0fe5904311713 /contrib/gcc/config/ia64
parentc9ab9ae440a8066b2c2b85b157b1fdadcf09916a (diff)
downloadFreeBSD-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.h16
-rw-r--r--contrib/gcc/config/ia64/elf.h6
-rw-r--r--contrib/gcc/config/ia64/freebsd.h10
-rw-r--r--contrib/gcc/config/ia64/hpux.h14
-rw-r--r--contrib/gcc/config/ia64/ia64-protos.h4
-rw-r--r--contrib/gcc/config/ia64/ia64.c322
-rw-r--r--contrib/gcc/config/ia64/ia64.h59
-rw-r--r--contrib/gcc/config/ia64/ia64.md33
-rw-r--r--contrib/gcc/config/ia64/linux.h22
-rw-r--r--contrib/gcc/config/ia64/sysv4.h5
-rw-r--r--contrib/gcc/config/ia64/unwind-ia64.c298
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(&regs[kind - 1], sr->curr.reg + limit[kind - 1],
- sr->region_start + t);
+ spill_next_when (&regs[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;
OpenPOWER on IntegriCloud