aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn David Anglin <dave@hiauly1.hia.nrc.ca>2002-04-04 02:48:18 +0000
committerJohn David Anglin <danglin@gcc.gnu.org>2002-04-04 02:48:18 +0000
commit823fbbce5c867613d9a1417d77970ab0ea5f41b4 (patch)
tree581f501853359286f80b37739491cd24a96a7357
parent4078e2240c57c6d1ad5737de12b724f90d79a612 (diff)
downloadgcc-823fbbce5c867613d9a1417d77970ab0ea5f41b4.zip
gcc-823fbbce5c867613d9a1417d77970ab0ea5f41b4.tar.gz
gcc-823fbbce5c867613d9a1417d77970ab0ea5f41b4.tar.bz2
pa-linux.h (INCOMING_RETURN_ADDR_RTX): Move.
* pa-linux.h (INCOMING_RETURN_ADDR_RTX): Move. (DWARF_FRAME_RETURN_COLUMN): Move. (ASM_PREFERRED_EH_DATA_FORMAT): Define. (ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX): Define. * pa.c (except.h, predict.h): Include. (FRP): Delete. (store_reg_modify, set_reg_plus_d): Revise prototypes. (output_ascii): Add cast. (store_reg_modify): Revise to add frame notes. (set_reg_plus_d): Likewise. (compute_frame_size): Include space for eh data registers in frame if the current function calls eh_return. (hppa_expand_prologue): Ensure register %r2 is saved if the current function calls eh_return. Save eh data registers if the current function calls eh_return. Fix code to add frame notes. Emit blockage to prevent insns with frame notes being scheduled in the delay slot of calls. (hppa_expand_epilogue): Restore eh data registers and do final stack adjustment if the current function calls eh_return. Don't add frame notes. (output_call): Revise for change in length of call insn. Don't do return pointer adjustment for an unconditional jump in the delay slot of a call when using frame notes. * pa.h (EH_RETURN_DATA_REGNO): Revise for TARGET_64BIT compatibility. (EH_RETURN_HANDLER_RTX): Use saved value on stack. (ARG_POINTER_CFA_OFFSET): Define. * pa.md (return_external_pic): New pattern. (prologue): Correct formatting. Use return_external_pic if current function calls eh_return. (call_internal_symref, call_value_internal_symref, sibcall_internal_symref, sibcall_value_internal_symref): Change default lengths of short, long non-pic, and long pic calls to 8, 68, and 84, respectively. (exception_receiver): Use hppa_pic_save_rtx () to restore pic register. * configure.in ("assembler dwarf2 debug_line support"): Add hppa*-*-* to list of targets to check using "nop" insn. * configure: Rebuilt. From-SVN: r51836
-rw-r--r--gcc/ChangeLog41
-rw-r--r--gcc/config/pa/pa-linux.h39
-rw-r--r--gcc/config/pa/pa.c395
-rw-r--r--gcc/config/pa/pa.h16
-rw-r--r--gcc/config/pa/pa.md94
-rwxr-xr-xgcc/configure24
-rw-r--r--gcc/configure.in2
7 files changed, 428 insertions, 183 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7bec6d5..7446680 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,44 @@
+2002-04-03 John David Anglin <dave@hiauly1.hia.nrc.ca>
+
+ * pa-linux.h (INCOMING_RETURN_ADDR_RTX): Move.
+ (DWARF_FRAME_RETURN_COLUMN): Move.
+ (ASM_PREFERRED_EH_DATA_FORMAT): Define.
+ (ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX): Define.
+ * pa.c (except.h, predict.h): Include.
+ (FRP): Delete.
+ (store_reg_modify, set_reg_plus_d): Revise prototypes.
+ (output_ascii): Add cast.
+ (store_reg_modify): Revise to add frame notes.
+ (set_reg_plus_d): Likewise.
+ (compute_frame_size): Include space for eh data registers in frame if
+ the current function calls eh_return.
+ (hppa_expand_prologue): Ensure register %r2 is saved if the current
+ function calls eh_return. Save eh data registers if the current
+ function calls eh_return. Fix code to add frame notes. Emit
+ blockage to prevent insns with frame notes being scheduled in the
+ delay slot of calls.
+ (hppa_expand_epilogue): Restore eh data registers and do final stack
+ adjustment if the current function calls eh_return. Don't add frame
+ notes.
+ (output_call): Revise for change in length of call insn. Don't do
+ return pointer adjustment for an unconditional jump in the delay slot
+ of a call when using frame notes.
+ * pa.h (EH_RETURN_DATA_REGNO): Revise for TARGET_64BIT compatibility.
+ (EH_RETURN_HANDLER_RTX): Use saved value on stack.
+ (ARG_POINTER_CFA_OFFSET): Define.
+ * pa.md (return_external_pic): New pattern.
+ (prologue): Correct formatting. Use return_external_pic if current
+ function calls eh_return.
+ (call_internal_symref, call_value_internal_symref,
+ sibcall_internal_symref, sibcall_value_internal_symref): Change default
+ lengths of short, long non-pic, and long pic calls to 8, 68, and 84,
+ respectively.
+ (exception_receiver): Use hppa_pic_save_rtx () to restore pic register.
+
+ * configure.in ("assembler dwarf2 debug_line support"): Add hppa*-*-* to
+ list of targets to check using "nop" insn.
+ * configure: Rebuilt.
+
2002-04-04 Alan Modra <amodra@bigpond.net.au>
* config/rs6000/t-linux64 (EXTRA_MULTILIB_PARTS): Define.
diff --git a/gcc/config/pa/pa-linux.h b/gcc/config/pa/pa-linux.h
index f30a187..16599ef 100644
--- a/gcc/config/pa/pa-linux.h
+++ b/gcc/config/pa/pa-linux.h
@@ -24,6 +24,39 @@ Boston, MA 02111-1307, USA. */
#define DWARF2_ASM_LINE_DEBUG_INFO 1
#define DWARF2_UNWIND_INFO 1
+/* A C expression whose value is RTL representing the location of the
+ incoming return address at the beginning of any function, before the
+ prologue. You only need to define this macro if you want to support
+ call frame debugging information like that provided by DWARF 2. */
+#define INCOMING_RETURN_ADDR_RTX (gen_rtx_REG (word_mode, 2))
+#define DWARF_FRAME_RETURN_COLUMN (DWARF_FRAME_REGNUM (2))
+
+/* This macro chooses the encoding of pointers embedded in the exception
+ handling sections. If at all possible, this should be defined such
+ that the exception handling section will not require dynamic relocations,
+ and so may be read-only.
+
+ FIXME: We use DW_EH_PE_aligned to output a PLABEL constructor for
+ global function pointers. */
+#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) \
+ (CODE == 2 && GLOBAL ? DW_EH_PE_aligned : DW_EH_PE_absptr)
+
+/* Handle special EH pointer encodings. Absolute, pc-relative, and
+ indirect are handled automatically. Since pc-relative encoding is
+ not possible on the PA and we don't have the infrastructure for
+ data relative encoding, we use aligned plabels for global function
+ pointers. */
+#define ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX(FILE, ENCODING, SIZE, ADDR, DONE) \
+ do { \
+ if (((ENCODING) & 0x0F) == DW_EH_PE_aligned) \
+ { \
+ fputs (integer_asm_op (SIZE, FALSE), FILE); \
+ fputs ("P%", FILE); \
+ assemble_name (FILE, XSTR (ADDR, 0)); \
+ goto DONE; \
+ } \
+ } while (0)
+
#undef CPP_PREDEFINES
#define CPP_PREDEFINES "-D__ELF__ -Dunix -D__hppa__ -Dlinux -Asystem=unix -Asystem=posix -Acpu=hppa -Amachine=hppa -Amachine=bigendian"
@@ -64,12 +97,6 @@ Boston, MA 02111-1307, USA. */
else \
readonly_data_section ();
-/* A C expression whose value is RTL representing the location of the
- incoming return address at the beginning of any function, before the
- prologue. */
-#define INCOMING_RETURN_ADDR_RTX (gen_rtx_REG (word_mode, 2))
-#define DWARF_FRAME_RETURN_COLUMN (DWARF_FRAME_REGNUM (2))
-
/* Define the strings used for the special svr4 .type and .size directives.
These strings generally do not vary from one system running svr4 to
another, but if a given system (e.g. m88k running svr) needs to use
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index 16f6533..7890958 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA. */
#include "insn-attr.h"
#include "flags.h"
#include "tree.h"
+#include "except.h"
#include "expr.h"
#include "optabs.h"
#include "libfuncs.h"
@@ -43,6 +44,7 @@ Boston, MA 02111-1307, USA. */
#include "toplev.h"
#include "ggc.h"
#include "recog.h"
+#include "predict.h"
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
@@ -55,18 +57,6 @@ Boston, MA 02111-1307, USA. */
#endif
#endif
-#if DO_FRAME_NOTES
-#define FRP(INSN) \
- do \
- { \
- rtx insn = INSN; \
- RTX_FRAME_RELATED_P (insn) = 1; \
- } \
- while (0)
-#else
-#define FRP(INSN) INSN
-#endif
-
#ifndef FUNC_BEGIN_PROLOG_LABEL
#define FUNC_BEGIN_PROLOG_LABEL "LFBP"
#endif
@@ -83,8 +73,9 @@ static int compute_movstrsi_length PARAMS ((rtx));
static bool pa_assemble_integer PARAMS ((rtx, unsigned int, int));
static void remove_useless_addtr_insns PARAMS ((rtx, int));
static void store_reg PARAMS ((int, int, int));
+static void store_reg_modify PARAMS ((int, int, int));
static void load_reg PARAMS ((int, int, int));
-static void set_reg_plus_d PARAMS ((int, int, int));
+static void set_reg_plus_d PARAMS ((int, int, int, int));
static void pa_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
static int pa_adjust_cost PARAMS ((rtx, rtx, rtx, int));
static int pa_adjust_priority PARAMS ((rtx, int));
@@ -2662,7 +2653,7 @@ output_ascii (file, p, size)
fputs ("\"\n\t.STRING \"", file);
chars_output = 0;
}
- fwrite (partial_output, 1, co, file);
+ fwrite (partial_output, 1, (size_t) co, file);
chars_output += co;
co = 0;
}
@@ -2933,15 +2924,60 @@ store_reg (reg, disp, base)
RTX_FRAME_RELATED_P (insn) = 1;
}
-/* Emit RTL to set REG to the value specified by BASE+DISP.
- Handle case where DISP > 8k by using the add_high_const patterns.
+/* Emit RTL to store REG at the memory location specified by BASE and then
+ add MOD to BASE. MOD must be <= 8k. */
- Note in DISP > 8k case, we will leave the high part of the address
- in %r1. There is code in expand_hppa_{prologue,epilogue} that knows this.*/
+static void
+store_reg_modify (base, reg, mod)
+ int base, reg, mod;
+{
+ rtx insn, basereg, srcreg, delta;
+
+ if (! VAL_14_BITS_P (mod))
+ abort ();
+
+ basereg = gen_rtx_REG (Pmode, base);
+ srcreg = gen_rtx_REG (word_mode, reg);
+ delta = GEN_INT (mod);
+
+ insn = emit_insn (gen_post_store (basereg, srcreg, delta));
+ if (DO_FRAME_NOTES)
+ {
+ RTX_FRAME_RELATED_P (insn) = 1;
+
+ /* RTX_FRAME_RELATED_P must be set on each frame related set
+ in a parallel with more than one element. Don't set
+ RTX_FRAME_RELATED_P in the first set if reg is temporary
+ register 1. The effect of this operation is recorded in
+ the initial copy. */
+ if (reg != 1)
+ {
+ RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, 0)) = 1;
+ RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, 1)) = 1;
+ }
+ else
+ {
+ /* The first element of a PARALLEL is always processed if it is
+ a SET. Thus, we need an expression list for this case. */
+ REG_NOTES (insn)
+ = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (VOIDmode, basereg,
+ gen_rtx_PLUS (word_mode, basereg, delta)),
+ REG_NOTES (insn));
+ }
+ }
+}
+
+/* Emit RTL to set REG to the value specified by BASE+DISP. Handle case
+ where DISP > 8k by using the add_high_const patterns. NOTE indicates
+ whether to add a frame note or not.
+
+ In the DISP > 8k case, we leave the high part of the address in %r1.
+ There is code in expand_hppa_{prologue,epilogue} that knows about this. */
static void
-set_reg_plus_d (reg, base, disp)
- int reg, base, disp;
+set_reg_plus_d (reg, base, disp, note)
+ int reg, base, disp, note;
{
rtx insn;
@@ -2963,7 +2999,7 @@ set_reg_plus_d (reg, base, disp)
delta));
}
- if (DO_FRAME_NOTES && reg == STACK_POINTER_REGNUM)
+ if (DO_FRAME_NOTES && note)
RTX_FRAME_RELATED_P (insn) = 1;
}
@@ -2981,6 +3017,18 @@ compute_frame_size (size, fregs_live)
of them at the same time. */
fsize = size + (size || frame_pointer_needed ? STARTING_FRAME_OFFSET : 0);
+ /* If the current function calls __builtin_eh_return, then we need
+ to allocate stack space for registers that will hold data for
+ the exception handler. */
+ if (DO_FRAME_NOTES && current_function_calls_eh_return)
+ {
+ unsigned int i;
+
+ for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; ++i)
+ continue;
+ fsize += i * UNITS_PER_WORD;
+ }
+
/* Account for space used by the callee general register saves. */
for (i = 18; i >= 3; i--)
if (regs_ever_live[i])
@@ -3108,7 +3156,7 @@ hppa_expand_prologue ()
int size = get_frame_size ();
int merge_sp_adjust_with_store = 0;
int i, offset;
- rtx tmpreg, size_rtx;
+ rtx insn, tmpreg;
gr_saved = 0;
fr_saved = 0;
@@ -3126,12 +3174,11 @@ hppa_expand_prologue ()
/* Compute a few things we will use often. */
tmpreg = gen_rtx_REG (word_mode, 1);
- size_rtx = GEN_INT (actual_fsize);
/* Save RP first. The calling conventions manual states RP will
always be stored into the caller's frame at sp - 20 or sp - 16
depending on which ABI is in use. */
- if (regs_ever_live[2])
+ if (regs_ever_live[2] || current_function_calls_eh_return)
store_reg (2, TARGET_64BIT ? -16 : -20, STACK_POINTER_REGNUM);
/* Allocate the local frame and set up the frame pointer if needed. */
@@ -3141,36 +3188,30 @@ hppa_expand_prologue ()
{
/* Copy the old frame pointer temporarily into %r1. Set up the
new stack pointer, then store away the saved old frame pointer
- into the stack at sp+actual_fsize and at the same time update
- the stack pointer by actual_fsize bytes. Two versions, first
+ into the stack at sp and at the same time update the stack
+ pointer by actual_fsize bytes. Two versions, first
handles small (<8k) frames. The second handles large (>=8k)
frames. */
- emit_move_insn (tmpreg, frame_pointer_rtx);
- FRP (emit_move_insn (frame_pointer_rtx, stack_pointer_rtx));
- if (VAL_14_BITS_P (actual_fsize))
+ insn = emit_move_insn (tmpreg, frame_pointer_rtx);
+ if (DO_FRAME_NOTES)
{
- rtx insn = emit_insn (gen_post_store (stack_pointer_rtx, tmpreg,
- size_rtx));
- if (DO_FRAME_NOTES)
- {
- rtvec vec;
- RTX_FRAME_RELATED_P (insn) = 1;
- vec = gen_rtvec (2,
- gen_rtx_SET (VOIDmode,
- gen_rtx_MEM (word_mode,
- stack_pointer_rtx),
- frame_pointer_rtx),
- gen_rtx_SET (VOIDmode,
- stack_pointer_rtx,
- gen_rtx_PLUS (word_mode,
- stack_pointer_rtx,
- size_rtx)));
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
- gen_rtx_SEQUENCE (VOIDmode, vec),
- REG_NOTES (insn));
- }
+ /* We need to record the frame pointer save here since the
+ new frame pointer is set in the following insn. */
+ RTX_FRAME_RELATED_P (insn) = 1;
+ REG_NOTES (insn)
+ = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (VOIDmode,
+ gen_rtx_MEM (word_mode, stack_pointer_rtx),
+ frame_pointer_rtx),
+ REG_NOTES (insn));
}
+
+ insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+ if (DO_FRAME_NOTES)
+ RTX_FRAME_RELATED_P (insn) = 1;
+
+ if (VAL_14_BITS_P (actual_fsize))
+ store_reg_modify (STACK_POINTER_REGNUM, 1, actual_fsize);
else
{
/* It is incorrect to store the saved frame pointer at *sp,
@@ -3181,32 +3222,12 @@ hppa_expand_prologue ()
finish allocating the new frame. */
int adjust1 = 8192 - 64;
int adjust2 = actual_fsize - adjust1;
- rtx delta = GEN_INT (adjust1);
- rtx insn = emit_insn (gen_post_store (stack_pointer_rtx, tmpreg,
- delta));
- if (DO_FRAME_NOTES)
- {
- rtvec vec;
- RTX_FRAME_RELATED_P (insn) = 1;
- vec = gen_rtvec (2,
- gen_rtx_SET (VOIDmode,
- gen_rtx_MEM (word_mode,
- stack_pointer_rtx),
- frame_pointer_rtx),
- gen_rtx_SET (VOIDmode,
- stack_pointer_rtx,
- gen_rtx_PLUS (word_mode,
- stack_pointer_rtx,
- delta)));
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
- gen_rtx_SEQUENCE (VOIDmode, vec),
- REG_NOTES (insn));
- }
+ store_reg_modify (STACK_POINTER_REGNUM, 1, adjust1);
set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
- adjust2);
+ adjust2, 1);
}
+
/* Prevent register spills from being scheduled before the
stack pointer is raised. Necessary as we will be storing
registers using the frame pointer as a base register, and
@@ -3226,7 +3247,7 @@ hppa_expand_prologue ()
bytes. */
else
set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
- actual_fsize);
+ actual_fsize, 1);
}
}
@@ -3236,7 +3257,27 @@ hppa_expand_prologue ()
was done earlier. */
if (frame_pointer_needed)
{
- for (i = 18, offset = local_fsize; i >= 4; i--)
+ offset = local_fsize;
+
+ /* Saving the EH return data registers in the frame is the simplest
+ way to get the frame unwind information emitted. We put them
+ just before the general registers. */
+ if (DO_FRAME_NOTES && current_function_calls_eh_return)
+ {
+ unsigned int i, regno;
+
+ for (i = 0; ; ++i)
+ {
+ regno = EH_RETURN_DATA_REGNO (i);
+ if (regno == INVALID_REGNUM)
+ break;
+
+ store_reg (regno, offset, FRAME_POINTER_REGNUM);
+ offset += UNITS_PER_WORD;
+ }
+ }
+
+ for (i = 18; i >= 4; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
store_reg (i, offset, FRAME_POINTER_REGNUM);
@@ -3249,18 +3290,42 @@ hppa_expand_prologue ()
/* No frame pointer needed. */
else
{
- for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--)
+ offset = local_fsize - actual_fsize;
+
+ /* Saving the EH return data registers in the frame is the simplest
+ way to get the frame unwind information emitted. */
+ if (DO_FRAME_NOTES && current_function_calls_eh_return)
+ {
+ unsigned int i, regno;
+
+ for (i = 0; ; ++i)
+ {
+ regno = EH_RETURN_DATA_REGNO (i);
+ if (regno == INVALID_REGNUM)
+ break;
+
+ /* If merge_sp_adjust_with_store is nonzero, then we can
+ optimize the first save. */
+ if (merge_sp_adjust_with_store)
+ {
+ store_reg_modify (STACK_POINTER_REGNUM, regno, -offset);
+ merge_sp_adjust_with_store = 0;
+ }
+ else
+ store_reg (regno, offset, STACK_POINTER_REGNUM);
+ offset += UNITS_PER_WORD;
+ }
+ }
+
+ for (i = 18; i >= 3; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
/* If merge_sp_adjust_with_store is nonzero, then we can
optimize the first GR save. */
if (merge_sp_adjust_with_store)
{
- rtx delta = GEN_INT (-offset);
+ store_reg_modify (STACK_POINTER_REGNUM, i, -offset);
merge_sp_adjust_with_store = 0;
- FRP (emit_insn (gen_post_store (stack_pointer_rtx,
- gen_rtx_REG (word_mode, i),
- delta)));
}
else
store_reg (i, offset, STACK_POINTER_REGNUM);
@@ -3272,7 +3337,7 @@ hppa_expand_prologue ()
did any GR saves, then just emit the adjustment here. */
if (merge_sp_adjust_with_store)
set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
- actual_fsize);
+ actual_fsize, 1);
}
/* The hppa calling conventions say that %r19, the pic offset
@@ -3290,12 +3355,20 @@ hppa_expand_prologue ()
/* Floating point register store. */
if (save_fregs)
{
+ rtx base;
+
/* First get the frame or stack pointer to the start of the FP register
save area. */
if (frame_pointer_needed)
- set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset);
+ {
+ set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset, 0);
+ base = frame_pointer_rtx;
+ }
else
- set_reg_plus_d (1, STACK_POINTER_REGNUM, offset);
+ {
+ set_reg_plus_d (1, STACK_POINTER_REGNUM, offset, 0);
+ base = stack_pointer_rtx;
+ }
/* Now actually save the FP registers. */
for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
@@ -3310,20 +3383,49 @@ hppa_expand_prologue ()
if (DO_FRAME_NOTES)
{
RTX_FRAME_RELATED_P (insn) = 1;
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
- gen_rtx_SET (VOIDmode,
- gen_rtx_MEM (DFmode,
- plus_constant (stack_pointer_rtx,
- offset)),
- reg),
- REG_NOTES (insn));
+ if (TARGET_64BIT)
+ {
+ rtx mem = gen_rtx_MEM (DFmode,
+ plus_constant (base, offset));
+ REG_NOTES (insn)
+ = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (VOIDmode, mem, reg),
+ REG_NOTES (insn));
+ }
+ else
+ {
+ rtx meml = gen_rtx_MEM (SFmode,
+ plus_constant (base, offset));
+ rtx memr = gen_rtx_MEM (SFmode,
+ plus_constant (base, offset + 4));
+ rtx regl = gen_rtx_REG (SFmode, i);
+ rtx regr = gen_rtx_REG (SFmode, i + 1);
+ rtx setl = gen_rtx_SET (VOIDmode, meml, regl);
+ rtx setr = gen_rtx_SET (VOIDmode, memr, regr);
+ rtvec vec;
+
+ RTX_FRAME_RELATED_P (setl) = 1;
+ RTX_FRAME_RELATED_P (setr) = 1;
+ vec = gen_rtvec (2, setl, setr);
+ REG_NOTES (insn)
+ = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+ gen_rtx_SEQUENCE (VOIDmode, vec),
+ REG_NOTES (insn));
+ }
}
offset += GET_MODE_SIZE (DFmode);
fr_saved++;
}
}
}
+
+ /* FIXME: expand_call and expand_millicode_call need to be fixed to
+ prevent insns with frame notes being scheduled in the delay slot
+ of calls. This causes problems because the dwarf2 output code
+ processes the insn list serially. For now, limit the migration
+ of prologue insns with a blockage. */
+ if (DO_FRAME_NOTES)
+ emit_insn (gen_blockage ());
}
/* Emit RTL to load REG from the memory location specified by BASE+DISP.
@@ -3407,7 +3509,7 @@ hppa_expand_epilogue ()
/* Try to restore RP early to avoid load/use interlocks when
RP gets used in the return (bv) instruction. This appears to still
be necessary even when we schedule the prologue and epilogue. */
- if (regs_ever_live [2])
+ if (regs_ever_live [2] || current_function_calls_eh_return)
{
ret_off = TARGET_64BIT ? -16 : -20;
if (frame_pointer_needed)
@@ -3429,7 +3531,26 @@ hppa_expand_epilogue ()
/* General register restores. */
if (frame_pointer_needed)
{
- for (i = 18, offset = local_fsize; i >= 4; i--)
+ offset = local_fsize;
+
+ /* If the current function calls __builtin_eh_return, then we need
+ to restore the saved EH data registers. */
+ if (DO_FRAME_NOTES && current_function_calls_eh_return)
+ {
+ unsigned int i, regno;
+
+ for (i = 0; ; ++i)
+ {
+ regno = EH_RETURN_DATA_REGNO (i);
+ if (regno == INVALID_REGNUM)
+ break;
+
+ load_reg (regno, offset, FRAME_POINTER_REGNUM);
+ offset += UNITS_PER_WORD;
+ }
+ }
+
+ for (i = 18; i >= 4; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
load_reg (i, offset, FRAME_POINTER_REGNUM);
@@ -3438,7 +3559,34 @@ hppa_expand_epilogue ()
}
else
{
- for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--)
+ offset = local_fsize - actual_fsize;
+
+ /* If the current function calls __builtin_eh_return, then we need
+ to restore the saved EH data registers. */
+ if (DO_FRAME_NOTES && current_function_calls_eh_return)
+ {
+ unsigned int i, regno;
+
+ for (i = 0; ; ++i)
+ {
+ regno = EH_RETURN_DATA_REGNO (i);
+ if (regno == INVALID_REGNUM)
+ break;
+
+ /* Only for the first load.
+ merge_sp_adjust_with_load holds the register load
+ with which we will merge the sp adjustment. */
+ if (merge_sp_adjust_with_load == 0
+ && local_fsize == 0
+ && VAL_14_BITS_P (-actual_fsize))
+ merge_sp_adjust_with_load = regno;
+ else
+ load_reg (regno, offset, STACK_POINTER_REGNUM);
+ offset += UNITS_PER_WORD;
+ }
+ }
+
+ for (i = 18; i >= 3; i--)
{
if (regs_ever_live[i] && ! call_used_regs[i])
{
@@ -3464,9 +3612,9 @@ hppa_expand_epilogue ()
{
/* Adjust the register to index off of. */
if (frame_pointer_needed)
- set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset);
+ set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset, 0);
else
- set_reg_plus_d (1, STACK_POINTER_REGNUM, offset);
+ set_reg_plus_d (1, STACK_POINTER_REGNUM, offset, 0);
/* Actually do the restores now. */
for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
@@ -3491,45 +3639,36 @@ hppa_expand_epilogue ()
if (frame_pointer_needed)
{
rtx delta = GEN_INT (-64);
- rtx insn;
- set_reg_plus_d (STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM, 64);
- insn = emit_insn (gen_pre_load (frame_pointer_rtx, stack_pointer_rtx,
- delta));
- if (DO_FRAME_NOTES)
- {
- RTX_FRAME_RELATED_P (insn) = 1;
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
- gen_rtx_SET (VOIDmode, stack_pointer_rtx,
- gen_rtx_PLUS (word_mode, stack_pointer_rtx,
- delta)),
- REG_NOTES (insn));
- }
+
+ set_reg_plus_d (STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM, 64, 0);
+ emit_insn (gen_pre_load (frame_pointer_rtx, stack_pointer_rtx, delta));
}
/* If we were deferring a callee register restore, do it now. */
else if (merge_sp_adjust_with_load)
{
rtx delta = GEN_INT (-actual_fsize);
rtx dest = gen_rtx_REG (word_mode, merge_sp_adjust_with_load);
- rtx insn = emit_insn (gen_pre_load (dest, stack_pointer_rtx, delta));
- if (DO_FRAME_NOTES)
- {
- RTX_FRAME_RELATED_P (insn) = 1;
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
- gen_rtx_SET (VOIDmode, stack_pointer_rtx,
- gen_rtx_PLUS (word_mode, stack_pointer_rtx,
- delta)),
- REG_NOTES (insn));
- }
+
+ emit_insn (gen_pre_load (dest, stack_pointer_rtx, delta));
}
else if (actual_fsize != 0)
- set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM, - actual_fsize);
+ set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
+ - actual_fsize, 0);
/* If we haven't restored %r2 yet (no frame pointer, and a stack
frame greater than 8k), do so now. */
if (ret_off != 0)
load_reg (2, ret_off, STACK_POINTER_REGNUM);
+
+ if (DO_FRAME_NOTES && current_function_calls_eh_return)
+ {
+ rtx sa = EH_RETURN_STACKADJ_RTX;
+
+ emit_insn (gen_blockage ());
+ emit_insn (TARGET_64BIT
+ ? gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, sa)
+ : gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, sa));
+ }
}
rtx
@@ -6029,10 +6168,10 @@ output_call (insn, call_dest, sibcall)
and we're sure that the branch will reach the beginning of the $CODE$
subspace. */
if ((dbr_sequence_length () == 0
- && get_attr_length (insn) == 8)
+ && get_attr_length (insn) == 12)
|| (dbr_sequence_length () != 0
&& GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
- && get_attr_length (insn) == 4))
+ && get_attr_length (insn) == 8))
{
xoperands[0] = call_dest;
xoperands[1] = gen_rtx_REG (word_mode, sibcall ? 0 : 2);
@@ -6041,7 +6180,7 @@ output_call (insn, call_dest, sibcall)
}
/* This call may not reach the beginning of the $CODE$ subspace. */
- if (get_attr_length (insn) > 8)
+ if (get_attr_length (insn) > 12)
{
int delay_insn_deleted = 0;
rtx xoperands[2];
@@ -6241,14 +6380,16 @@ output_call (insn, call_dest, sibcall)
- INSN_ADDRESSES (INSN_UID (seq_insn)) - 8;
/* If the branch was too far away, emit a normal call followed
- by a nop, followed by the unconditional branch.
+ by a nop, followed by the unconditional branch. We also don't
+ adjust %r2 when generating dwarf2 frame or unwind info since
+ the adjustment confuses the dwarf2 output.
If the branch is close, then adjust %r2 from within the
call's delay slot. */
xoperands[0] = call_dest;
xoperands[1] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
- if (! VAL_14_BITS_P (distance))
+ if (DO_FRAME_NOTES || ! VAL_14_BITS_P (distance))
output_asm_insn ("{bl|b,l} %0,%%r2\n\tnop\n\tb,n %1", xoperands);
else
{
diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h
index 5d0955f..1390cae 100644
--- a/gcc/config/pa/pa.h
+++ b/gcc/config/pa/pa.h
@@ -506,10 +506,22 @@ extern struct rtx_def *hppa_pic_save_rtx PARAMS ((void));
#define STRUCT_VALUE_REGNUM 28
/* Describe how we implement __builtin_eh_return. */
+/* FIXME: What's a good choice for the EH data registers on TARGET_64BIT? */
#define EH_RETURN_DATA_REGNO(N) \
- ((N) < 3 ? (N) + 20 : (N) == 4 ? 31 : INVALID_REGNUM)
+ (TARGET_64BIT \
+ ? ((N) < 4 ? (N) + 4 : INVALID_REGNUM) \
+ : ((N) < 3 ? (N) + 20 : (N) == 4 ? 31 : INVALID_REGNUM))
#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, 29)
-#define EH_RETURN_HANDLER_RTX gen_rtx_REG (Pmode, 2)
+#define EH_RETURN_HANDLER_RTX \
+ gen_rtx_MEM (word_mode, \
+ gen_rtx_PLUS (word_mode, frame_pointer_rtx, \
+ TARGET_64BIT ? GEN_INT (-16) : GEN_INT (-20)))
+
+
+/* Offset from the argument pointer register value to the top of
+ stack. This is different from FIRST_PARM_OFFSET because of the
+ frame marker. */
+#define ARG_POINTER_CFA_OFFSET(FNDECL) 0
/* The letters I, J, K, L and M in a register constraint string
can be used to stand for particular ranges of immediate operands.
diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md
index aa0c305..ec83b1f 100644
--- a/gcc/config/pa/pa.md
+++ b/gcc/config/pa/pa.md
@@ -5568,6 +5568,21 @@
[(set_attr "type" "branch")
(set_attr "length" "4")])
+;; Use the PIC register to ensure it's restored after a
+;; call in PIC mode. This is used for eh returns which
+;; bypass the return stub.
+(define_insn "return_external_pic"
+ [(return)
+ (use (match_operand 0 "register_operand" "r"))
+ (use (reg:SI 2))
+ (clobber (reg:SI 1))]
+ "flag_pic
+ && current_function_calls_eh_return
+ && true_regnum (operands[0]) == PIC_OFFSET_TABLE_REGNUM"
+ "ldsid (%%sr0,%%r2),%%r1\;mtsp %%r1,%%sr0\;be%* 0(%%sr0,%%r2)"
+ [(set_attr "type" "branch")
+ (set_attr "length" "12")])
+
(define_expand "prologue"
[(const_int 0)]
""
@@ -5590,15 +5605,24 @@
/* Try to use the trivial return first. Else use the full
epilogue. */
if (hppa_can_use_return_insn_p ())
- emit_jump_insn (gen_return ());
+ emit_jump_insn (gen_return ());
else
{
rtx x;
hppa_expand_epilogue ();
if (flag_pic)
- x = gen_return_internal_pic (gen_rtx_REG (word_mode,
- PIC_OFFSET_TABLE_REGNUM));
+ {
+ rtx pic = gen_rtx_REG (word_mode, PIC_OFFSET_TABLE_REGNUM);
+
+ /* EH returns bypass the normal return stub. Thus, we must do an
+ interspace branch to return from functions that call eh_return.
+ This is only a problem for returns from shared code. */
+ if (current_function_calls_eh_return)
+ x = gen_return_external_pic (pic);
+ else
+ x = gen_return_internal_pic (pic);
+ }
else
x = gen_return_internal ();
emit_jump_insn (x);
@@ -5856,18 +5880,19 @@
[(set_attr "type" "call")
(set (attr "length")
;; If we're sure that we can either reach the target or that the
-;; linker can use a long-branch stub, then the length is 4 bytes.
+;; linker can use a long-branch stub, then the length is at most
+;; 8 bytes.
;;
-;; For long-calls the length will be either 52 bytes (non-pic)
-;; or 68 bytes (pic). */
+;; For long-calls the length will be at most 68 bytes (non-pic)
+;; or 84 bytes (pic). */
;; Else we have to use a long-call;
(if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 240000))
- (const_int 4)
+ (const_int 8)
(if_then_else (eq (symbol_ref "flag_pic")
(const_int 0))
- (const_int 52)
- (const_int 68))))])
+ (const_int 68)
+ (const_int 84))))])
(define_insn "call_internal_reg_64bit"
[(call (mem:SI (match_operand:DI 0 "register_operand" "r"))
@@ -6029,18 +6054,19 @@
[(set_attr "type" "call")
(set (attr "length")
;; If we're sure that we can either reach the target or that the
-;; linker can use a long-branch stub, then the length is 4 bytes.
+;; linker can use a long-branch stub, then the length is at most
+;; 8 bytes.
;;
-;; For long-calls the length will be either 52 bytes (non-pic)
-;; or 68 bytes (pic). */
+;; For long-calls the length will be at most 68 bytes (non-pic)
+;; or 84 bytes (pic). */
;; Else we have to use a long-call;
(if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 240000))
- (const_int 4)
+ (const_int 8)
(if_then_else (eq (symbol_ref "flag_pic")
(const_int 0))
- (const_int 52)
- (const_int 68))))])
+ (const_int 68)
+ (const_int 84))))])
(define_insn "call_value_internal_reg_64bit"
[(set (match_operand 0 "" "=rf")
@@ -6200,18 +6226,19 @@
[(set_attr "type" "call")
(set (attr "length")
;; If we're sure that we can either reach the target or that the
-;; linker can use a long-branch stub, then the length is 4 bytes.
+;; linker can use a long-branch stub, then the length is at most
+;; 8 bytes.
;;
-;; For long-calls the length will be either 52 bytes (non-pic)
-;; or 68 bytes (pic). */
+;; For long-calls the length will be at most 68 bytes (non-pic)
+;; or 84 bytes (pic). */
;; Else we have to use a long-call;
(if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 240000))
- (const_int 4)
+ (const_int 8)
(if_then_else (eq (symbol_ref "flag_pic")
(const_int 0))
- (const_int 52)
- (const_int 68))))])
+ (const_int 68)
+ (const_int 84))))])
(define_expand "sibcall_value"
[(parallel [(set (match_operand 0 "" "")
@@ -6258,18 +6285,19 @@
[(set_attr "type" "call")
(set (attr "length")
;; If we're sure that we can either reach the target or that the
-;; linker can use a long-branch stub, then the length is 4 bytes.
+;; linker can use a long-branch stub, then the length is at most
+;; 8 bytes.
;;
-;; For long-calls the length will be either 52 bytes (non-pic)
-;; or 68 bytes (pic). */
+;; For long-calls the length will be at most 68 bytes (non-pic)
+;; or 84 bytes (pic). */
;; Else we have to use a long-call;
(if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 240000))
- (const_int 4)
+ (const_int 8)
(if_then_else (eq (symbol_ref "flag_pic")
(const_int 0))
- (const_int 52)
- (const_int 68))))])
+ (const_int 68)
+ (const_int 84))))])
(define_insn "nop"
[(const_int 0)]
@@ -7216,16 +7244,12 @@
;; restore the PIC register.
(define_expand "exception_receiver"
[(const_int 4)]
- "!TARGET_PORTABLE_RUNTIME && flag_pic"
+ "flag_pic"
"
{
- /* Load the PIC register from the stack slot (in our caller's
- frame). */
- emit_move_insn (pic_offset_table_rtx,
- gen_rtx_MEM (SImode,
- plus_constant (stack_pointer_rtx, -32)));
- emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
- emit_insn (gen_blockage ());
+ /* Restore the PIC register using hppa_pic_save_rtx (). The
+ PIC register is not saved in the frame in 64-bit ABI. */
+ emit_move_insn (pic_offset_table_rtx, hppa_pic_save_rtx ());
DONE;
}")
diff --git a/gcc/configure b/gcc/configure
index 1270996..0c546ab 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -2229,7 +2229,7 @@ EOF
fi
# Find some useful tools
-for ac_prog in gawk mawk nawk awk
+for ac_prog in mawk gawk nawk awk
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
@@ -7480,7 +7480,7 @@ EOF
fi
echo $ac_n "checking assembler and linker support unaligned pc related relocs against hidden symbols""... $ac_c" 1>&6
-echo "configure:7430: checking assembler and linker support unaligned pc related relocs against hidden symbols" >&5
+echo "configure:7484: checking assembler and linker support unaligned pc related relocs against hidden symbols" >&5
if eval "test \"`echo '$''{'gcc_cv_as_sparc_ua_pcrel_hidden'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -7522,7 +7522,7 @@ EOF
case "$tm_file" in
*64*)
echo $ac_n "checking for 64 bit support in assembler ($gcc_cv_as)""... $ac_c" 1>&6
-echo "configure:7487: checking for 64 bit support in assembler ($gcc_cv_as)" >&5
+echo "configure:7526: checking for 64 bit support in assembler ($gcc_cv_as)" >&5
if eval "test \"`echo '$''{'gcc_cv_as_flags64'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -7567,7 +7567,7 @@ EOF
if test "x$gcc_cv_as_flags64" != xno; then
echo $ac_n "checking for assembler offsetable %lo() support""... $ac_c" 1>&6
-echo "configure:7532: checking for assembler offsetable %lo() support" >&5
+echo "configure:7571: checking for assembler offsetable %lo() support" >&5
if eval "test \"`echo '$''{'gcc_cv_as_offsetable_lo10'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -7607,7 +7607,7 @@ EOF
i[34567]86-*-* | x86_64-*-*)
echo $ac_n "checking assembler instructions""... $ac_c" 1>&6
-echo "configure:7572: checking assembler instructions" >&5
+echo "configure:7611: checking assembler instructions" >&5
gcc_cv_as_instructions=
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then
if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 9 -o "$gcc_cv_gas_major_version" -gt 2; then
@@ -7634,7 +7634,7 @@ EOF
echo "$ac_t""$gcc_cv_as_instructions" 1>&6
echo $ac_n "checking assembler GOTOFF in data directives""... $ac_c" 1>&6
-echo "configure:7599: checking assembler GOTOFF in data directives" >&5
+echo "configure:7638: checking assembler GOTOFF in data directives" >&5
gcc_cv_as_gotoff_in_data=no
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x
then
@@ -7664,7 +7664,7 @@ EOF
esac
echo $ac_n "checking assembler dwarf2 debug_line support""... $ac_c" 1>&6
-echo "configure:7629: checking assembler dwarf2 debug_line support" >&5
+echo "configure:7668: checking assembler dwarf2 debug_line support" >&5
gcc_cv_as_dwarf2_debug_line=no
# ??? Not all targets support dwarf2 debug_line, even within a version
# of gas. Moreover, we need to emit a valid instruction to trigger any
@@ -7673,7 +7673,7 @@ gcc_cv_as_dwarf2_debug_line=no
# ??? Once 2.11 is released, probably need to add first known working
# version to the per-target configury.
case "$target" in
- i?86*-*-* | mips*-*-* | alpha*-*-* | powerpc*-*-* | sparc*-*-* | m68*-*-* | x86_64*-*-*)
+ i?86*-*-* | mips*-*-* | alpha*-*-* | powerpc*-*-* | sparc*-*-* | m68*-*-* | x86_64*-*-* | hppa*-*-*)
insn="nop"
;;
ia64*-*-*)
@@ -7720,7 +7720,7 @@ fi
echo "$ac_t""$gcc_cv_as_dwarf2_debug_line" 1>&6
echo $ac_n "checking assembler --gdwarf2 support""... $ac_c" 1>&6
-echo "configure:7685: checking assembler --gdwarf2 support" >&5
+echo "configure:7724: checking assembler --gdwarf2 support" >&5
gcc_cv_as_gdwarf2_flag=no
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x;
then
@@ -7749,7 +7749,7 @@ fi
echo "$ac_t""$gcc_cv_as_gdwarf2_flag" 1>&6
echo $ac_n "checking assembler --gstabs support""... $ac_c" 1>&6
-echo "configure:7714: checking assembler --gstabs support" >&5
+echo "configure:7753: checking assembler --gstabs support" >&5
gcc_cv_as_gstabs_flag=no
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x;
then
@@ -7777,7 +7777,7 @@ fi
echo "$ac_t""$gcc_cv_as_gstabs_flag" 1>&6
echo $ac_n "checking linker PT_GNU_EH_FRAME support""... $ac_c" 1>&6
-echo "configure:7742: checking linker PT_GNU_EH_FRAME support" >&5
+echo "configure:7781: checking linker PT_GNU_EH_FRAME support" >&5
gcc_cv_ld_eh_frame_hdr=no
if test x$gcc_cv_gld_major_version != x -a x$gcc_cv_gld_minor_version != x; then
if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 12 -o "$gcc_cv_gld_major_version" -gt 2 && grep 'EMUL = elf' ../ld/Makefile > /dev/null; then
@@ -7940,7 +7940,7 @@ fi
echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6
-echo "configure:7905: checking whether to enable maintainer-specific portions of Makefiles" >&5
+echo "configure:7944: checking whether to enable maintainer-specific portions of Makefiles" >&5
# Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
if test "${enable_maintainer_mode+set}" = set; then
enableval="$enable_maintainer_mode"
diff --git a/gcc/configure.in b/gcc/configure.in
index 7abf01b..0e48cb4 100644
--- a/gcc/configure.in
+++ b/gcc/configure.in
@@ -1929,7 +1929,7 @@ gcc_cv_as_dwarf2_debug_line=no
# ??? Once 2.11 is released, probably need to add first known working
# version to the per-target configury.
case "$target" in
- i?86*-*-* | mips*-*-* | alpha*-*-* | powerpc*-*-* | sparc*-*-* | m68*-*-* | x86_64*-*-*)
+ i?86*-*-* | mips*-*-* | alpha*-*-* | powerpc*-*-* | sparc*-*-* | m68*-*-* | x86_64*-*-* | hppa*-*-*)
insn="nop"
;;
ia64*-*-*)